JS LeeCode剑指Offer刷题记录(持续更新)

直接随机开始做题,所以乱序

剑指Offer

      • 13.机器人的运动范围(广度优先遍历BFS)
      • 32 - I. 从上到下打印二叉树
      • 03. 数组中重复的数字
      • 20. 表示数值的字符串
      • 52. 两个链表的第一个公共节点
      • 56 - I. 数组中数字出现的次数
      • 56 - II. 数组中数字出现的次数 II
      • 57. 和为s的两个数字
      • 10- I. 斐波那契数列
      • 25. 合并两个排序的链表
      • 48. 最长不含重复字符的子字符串

13.机器人的运动范围(广度优先遍历BFS)

JS LeeCode剑指Offer刷题记录(持续更新)_第1张图片
分析题目:

  1. 限制条件:边界判断
  2. 数位求和:行坐标和列坐标数位只和不大于k
  3. 四周方向的遍历
  4. 统计格子数

解决方案:

//边界判断
offsetX < 0 ||
offsetX >= m ||
offsetY < 0 ||
offsetY >= n
// 数位求和
// 1.使用循环取余数相加
function getSum(num) {
  let sum = 0;
  while (num) {
    sum += num % 10;
    num = Math.floor(num / 10);
  }
  return sum;
}

// 2.使用字符串累加
function getSum(num) {
  let stringAry = num.toString().split("");
  return stringAry.reduce((a, b) => Number(a) + Number(b), 0);
}
// 四周方向遍历
// 1.使用方向数组遍历
const directionArr = [
  [0, 1], //下
  [1, 0], //右
];
for (let i = 0; i < 2; i++) {
  let offsetX = x + directionArr[i][0];
  let offsetY = y + directionArr[i][1];
  // ...
}

//2.递归遍历(重复调用函数)
dfs(i + 1, j); //右
dfs(i, j + 1); //下
// 统计格子数
// 1.使用Set.size
// 走过的格子用Set代替Map进行保存
set.add(`${offsetX},${offsetY}`);
return set.size;

// 2.设置count变量,符合条件就++
if (条件成立) count++;

示例代码:

/**
 * @param {number} m
 * @param {number} n
 * @param {number} k
 * @return {number}
 */
var movingCount = function (m, n, k) {
  // 数位和函数getSum
  function getSum(num) {
    let sum = 0;
    while (num) {
      sum += num % 10;
      num = Math.floor(num / 10);
    }
    return sum;
  }
  // 方向数组directionArr
  // 这里优化后只需要向下和向右走
  const directionArr = [
    [0, 1],
    [1, 0],
  ];
  // 存储已经走过的坐标(利用Set函数的唯一性)
  let set = new Set(["0,0"]);
  // 创建队列
  let queue = [[0, 0]];
  while (queue.length) {
    // 删除队列首项
    let [x, y] = queue.shift();
    // 遍历方向
    for (let i = 0; i < 2; i++) {
      let offsetX = x + directionArr[i][0];
      let offsetY = y + directionArr[i][1];
      // 临界值判断+限制条件判断
      if (
        offsetX < 0 ||
        offsetX >= m ||
        offsetY < 0 ||
        offsetY >= n ||
        getSum(offsetX) + getSum(offsetY) > k ||
        set.has(`${offsetX},${offsetY}`)
      ) {
        continue;
      }
      set.add(`${offsetX},${offsetY}`);
      queue.push([offsetX, offsetY]);
    }
  }
  return set.size;
};

32 - I. 从上到下打印二叉树

JS LeeCode剑指Offer刷题记录(持续更新)_第2张图片
题目分析:
是二叉树的层序遍历

解决方案:
利用队列来做

示例代码:

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var levelOrder = function(root) {
    if(!root) return [];
    let data=[];
    let queue=[root];
    while(queue.length){
        let first=queue.shift();
        data.push(first.val);
        if(first.left) queue.push(first.left);
        if(first.right) queue.push(first.right);
    }
    return data;
};

03. 数组中重复的数字

JS LeeCode剑指Offer刷题记录(持续更新)_第3张图片
题目分析:

  1. 有数字重复
  2. 重复次数不确定
  3. 返回任意一个重复的数字

解决方案:

// 1.使用哈希表
var findRepeatNumber = function (nums) {
  // 新建哈希表
  let map = new Map();
  // 遍历数组,未出现过的值为1,重复出现则直接返回数字
  for (let num of nums) {
    if (map.has(num)) {
      return num;
    } else map.set(num, 1);
  }
};
// 2.使用lastIndexOf
var findRepeatNumber = function (nums) {
  for (let num of nums) {
    if (nums.indexOf(num) !== nums.lastIndexOf(num)) return num;
  }
};
// 3.使用Set函数
var findRepeatNumber = function (nums) {
  let s = new Set();
  for (var i in nums) {
    var curLenth = s.size;
    s.add(nums[i]);
    if (s.size == curLenth) return nums[i];
  }
};

20. 表示数值的字符串

在这里插入图片描述
题目分析:

  1. 字符串是否表示数值
  2. 包括整数和小数

解决方案:

// 1.使用正则判断
var isNumber = function (s) {
  return /^[+-]?(\d+(\.\d*)?|(\.\d+))(e[+-]?\d+)?$/.test(s.trim());
};
// 2.isNaN判断
var isNumber = function (s) {
  s = s.trim();
  if (!s) return false;
  return !isNaN(s);
};

52. 两个链表的第一个公共节点

JS LeeCode剑指Offer刷题记录(持续更新)_第4张图片
题目分析:

  1. 有两个链表
  2. 找出第一个公共结点

解决方案:

// 1.哈希表遍历
var getIntersectionNode = function (headA, headB) {
  let map = new Map();
  let node = headA;
  while (node) {
    map.set(node, true);
    node = node.next;
  }
  node = headB;
  while (node) {
    if (map.has(node)) return node;
    else node = node.next;
  }
  return null;
};
// 2.快慢指针,双指针
var getIntersectionNode = function (headA, headB) {
  let lenA = 0;
  let lenB = 0;
  let diff = 0;
  let node = headA;
  while (node) {
    ++lenA;
    node = node.next;
  }
  node = headB;
  while (node) {
    ++lenB;
    node = node.next;
  }
  diff = lenA - lenB;
  let slow, fast;
  if (diff > 0) {
    slow = headA;
    fast = headB;
  } else {
    slow = headB;
    fast = headA;
    diff = -diff;
  }
  while (diff--) {
    slow = slow.next;
  }
  while (slow !== fast) {
    slow = slow.next;
    fast = fast.next;
  }
  return slow;
};

56 - I. 数组中数字出现的次数

JS LeeCode剑指Offer刷题记录(持续更新)_第5张图片
题目分析:

  1. 只出现一次的数字只有两个
  2. 其他重复出现的数字都只出现了两次
  3. 时间复杂度O(n),意味着不能嵌套循环
  4. 空间复杂度O(1),意味着不能开辟新数组

解决方案:

// 1.用对象来解决
var singleNumbers = function (nums) {
  var obj = {};
  nums.forEach((count) => {
    let attr = count + "";
    // 存在属性就删除,最后剩下就是两个不重复的属性
    obj[attr] ? delete obj[attr] : (obj[attr] = 1);
  });
  return Object.keys(obj);
};
// 2.利用位运算
var singleNumbers = function (nums) {
  let mask = 0;
  for (let num of nums) {
    mask ^= num;
  }
  // mask相当于两个出现次数为1的数的异或即mask=num1^num2
  const diff = mask & -mask;
  // diff相当于num1和num2二进制中出现不相等的地方
  // 将数与diff进行与运算,为1的一组,为0一组就区分开了
  let num1 = 0;
  let num2 = 0;
  for (let num of nums) {
    if (num & diff) {
      num1 ^= num;
    } else {
      num2 ^= num2;
    }
  }
  return [num1, num2];
};

56 - II. 数组中数字出现的次数 II

JS LeeCode剑指Offer刷题记录(持续更新)_第6张图片
题目分析:

  1. 只有一个数字只出现一次
  2. 其他数字都出现了三次
  3. 返回的是只出现一次的数字

解决方案:

// 1.暴力循环解法
var singleNumber = function (nums) {
  let x = 0;
  // 新建一个计数数组
  let numCount = [];
  // 将技术数组清零
  for (let i = 0; i < nums.length; i++) {
    numCount[nums[i]] = 0;
  }
  // 循环遍历记录数字出现的个数
  for (let i = 0; i < nums.length; i++) {
    numCount[nums[i]]++;
  }
  // 循环遍历数组,计数为1的即为要找的数组
  for (let i = 0; i < nums.length; i++) {
    if (numCount[nums[i]] == 1) return nums[i];
  }
};
// 2.利用lastIndexOf
// lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索
var singleNumber = function (nums) {
  for (let i = 0; i < nums.length; i++) {
    if (nums.indexOf(nums[i]) === nums.lastIndexOf(nums[i])) return nums[i];
  }
};
// 3.哈希表做法
var singleNumber = function (nums) {
  // 新建一个哈希表
  const map = new Map();
  for (let num of nums) {
    // 计数存储到哈希表
    if (map.has(num)) map.set(num, map.get(num) + 1);
    else map.set(num, 1);
  }
  // 遍历哈希表,找出次数为1的数
  for (let [num, times] of map.entries()) {
    if (times === 1) return num;
  }
};

57. 和为s的两个数字

JS LeeCode剑指Offer刷题记录(持续更新)_第7张图片
题目分析:

  1. 给出一个递增排序数组,一个数字s
  2. 求任意两个数和为s
  3. 输出任意一对即可

解决方案:

//  双指针
var twoSum = function (nums, target) {
  let left = 0,
    right = nums.length - 1;
  while (left <= right) {
    if (nums[left] + nums[right] === target) {
      return [nums[left], nums[right]];
    } else if (nums[left] + nums[right] < target) {
      ++left;
    } else {
      --right;
    }
  }
};

10- I. 斐波那契数列

JS LeeCode剑指Offer刷题记录(持续更新)_第8张图片
题目分析:

  1. 已给出定义
  2. 参数为n
  3. 递推关系

解决方案:

// 1.数学定义
var fib = function (n) {
  if (n === 0) return 0;
  if (n === 1) return 1;
  let res1 = 0;
  let res2 = 1;
  for (let i = 1; i < n; i++) {
    let t = res1;
    res1 = res2;
    res2 = (t + res2) % 1000000007;
  }
  return res2;
};

// 2.动态规划+“备忘录”(缓存)
var fib = function (n) {
  const cache = {
    0: 0n,
    1: 1n,
  };
  return Fibonacci(n) % 1000000007n;
  function Fibonacci(n) {
    if (cache[n] !== undefined) {
      return cache[n];
    }
    cache[n] = Fibonacci(n - 1) + Fibonacci(n - 2);
    return cache[n];
  }
};

赶时间这里开始只写一种解法

25. 合并两个排序的链表

JS LeeCode剑指Offer刷题记录(持续更新)_第9张图片

//迭代
var mergeTwoLists = function(l1, l2) {
    if(!l1) return l2;
    if(!l2) return l1;
    if(l1.val>l2.val){
        l2.next=mergeTwoLists(l1,l2.next);
        return l2;
    }else{
        l1.next=mergeTwoLists(l1.next,l2);
        return l1;
    }
};

48. 最长不含重复字符的子字符串

JS LeeCode剑指Offer刷题记录(持续更新)_第10张图片

var lengthOfLongestSubstring = function(s) {
    const length = s.length;
    const map = new Map();
    let i = 0,
        j = 0;
    let ans = 0;
    while (i < length && j < length) {
        if (map.has(s[j]) && map.get(s[j]) >= i) {
            i = map.get(s[j]) + 1;
        }
        ans = Math.max(j - i + 1, ans);
        map.set(s[j], j);
        ++j;
    }
    return ans;
};

你可能感兴趣的:(算法)