js解leetcode(71)-中等

1.骑士拨号器

题目:

国际象棋中的骑士可以按下图所示进行移动:

   
这一次,我们将 “骑士” 放在电话拨号盘的任意数字键(如上图所示)上,接下来,骑士将会跳 N-1 步。每一步必须是从一个数字键跳到另一个数字键。

每当它落在一个键上(包括骑士的初始位置),都会拨出键所对应的数字,总共按下 N 位数字。

你能用这种方式拨出多少个不同的号码?

因为答案可能很大,所以输出答案模 10^9 + 7。

思路:先观察键盘,然后可以记录每个键对应的下一个键的可能性。

然后用类似BFS的思路,记录每一步落在各个数字上的的可能性,然后以此计算下一步的各种的可能,用两个数组分别记录这一步和上一步的结果

时间复杂度O(N),空间复杂度O(1)

/**
 * @param {number} n
 * @return {number}
 */
var knightDialer = function(n) {
  const map = new Map();
  const mod = Math.pow(10, 9) + 7;
  map.set(1, [6, 8]);
  map.set(2, [7, 9]);
  map.set(3, [4, 8]);
  map.set(4, [0, 3, 9]);
  map.set(5, []);
  map.set(6, [0, 1, 7]);
  map.set(7, [2, 6]);
  map.set(8, [1, 3]);
  map.set(9, [2, 4]);
  map.set(0, [4, 6]);
  const dp1 = new Array(10).fill(1);
  const dp2 = new Array(10).fill(0);
  while (--n) {
    for (let i = 0; i < 10; i++) {
      map.get(i).forEach((item) => {
        dp2[item] = (dp2[item] + dp1[i]) % mod;
      });
    }
    for (let i = 0; i < 10; i++) {
      dp1[i] = dp2[i];
      dp2[i] = 0;
    }
  }
  return dp1.reduce((a, b) => (a + b) % mod, 0);
};

2.最小面积矩形

题目:

给定在 xy 平面上的一组点,确定由这些点组成的矩形的最小面积,其中矩形的边平行于 x 轴和 y 轴。

如果没有任何矩形,就返回 0。

思路:双重遍历所有的点,如果这两个点在x/y轴的坐标值都不同,那么判断对应另外两个端点的坐标是否在数组内,在的话计算矩形面积并更新最大值

时间复杂度O(n2),空间复杂度O(1)

/**
 * @param {number[][]} points
 * @return {number}
 */
var minAreaRect = function(points) {
  const set = new Set(points.map((item) => `${item[0]}-${item[1]}`));
  const l = points.length;
  let min = Infinity;

  for (let i = 0; i < l - 1; i++) {
    for (let j = i + 1; j < l; j++) {
      const leftup = points[i];
      const rightdown = points[j];

      if (leftup[0] !== rightdown[0] && leftup[1] !== rightdown[1]) {
        if (
          set.has(`${leftup[0]}-${rightdown[1]}`) &&
          set.has(`${rightdown[0]}-${leftup[1]}`)
        ) {
          const cur =
            Math.abs(leftup[0] - rightdown[0]) *
            Math.abs(leftup[1] - rightdown[1]);
          min = Math.min(min, cur);
        }
      }
    }
  }
  return min === Infinity ? 0 : min;
};

3.使数组唯一的最小增量

题目:

给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1

返回使 A 中的每个值都是唯一的最少操作次数。

思路:先对数组排序,然后按照贪心的思想,从第二个元素开始,最多时其比前一个元素大1.

时间复杂度O(nlogn),空间复杂度O(logn)
 

/**
 * @param {number[]} A
 * @return {number}
 */
var minIncrementForUnique = function(A) {
  A.sort((a, b) => a - b);
  let c = 0;
  const l = A.length;
  for (let i = 1; i < l; i++) {
    if (A[i] <= A[i - 1]) {
      c += A[i - 1] + 1 - A[i];
      A[i] = A[i - 1] + 1;
    }
  }
  return c;
};

4.验证栈序列

题目:

给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false 。

思路:过程模拟。用一个指针指向poped的第一个元素,pushed的元素肯定是从前往后推入的所以用一个栈将pushed的元素依次入栈,遇到和poped当前元素相同的时候,说明该元素出栈了,poped的指针右移,pushed的该元素删除,然后进行下一轮比较

时间复杂度O(n),空间复杂度O(n)

/**
 * @param {number[]} pushed
 * @param {number[]} popped
 * @return {boolean}
 */
var validateStackSequences = function(pushed, popped) {
  const l = pushed.length;
  const stack = [];
  let j = 0;
  for (const n of pushed) {
    stack.push(n);
    while (stack.length && j < l && stack[stack.length - 1] == popped[j]) {
      stack.pop();
      j++;
    }
  }

  return j === l;
};

5.移除最多的同行或者同列石头

题目:

n 块石头放置在二维平面中的一些整数坐标点上。每个坐标点上最多只能有一块石头。

如果一块石头的 同行或者同列 上有其他石头存在,那么就可以移除这块石头。

思路:典型的并查集。并且是两个方向上的查找,所以用双重循环枚举所有可能。

用一个数组记录每个石头对应的原始堆,如果它和另一个石头有交叉,那么把另一石头的原始堆指向自己的原始堆。

数组初始值为自身下标,每个不同即可

最后,数组中原始堆更改的石头,说明可以移动

时间复杂度O(n2),空间复杂度O(n)

/**
 * @param {number[][]} stones
 * @return {number}
 */
var removeStones = function (stones) {
  const l = stones.length;
  const parent = new Array(l).fill(0).map((value, index) => index);
  //合并同行同列的点 指向同一根节点
  for (let i = 0; i < l; i++) {
    for (let j = i + 1; j < l; j++) {
      if (stones[i][0] == stones[j][0] || stones[i][1] == stones[j][1]) {
        union(parent, i, j);
      }
    }
  }
  return parent.filter((item, index) => item !== index).length;
};
const union = (parent, i, j) => {
  parent[find(parent, j)] = find(parent, i);
};
const find = (parent, x) => {
  if (parent[x] != x) {
    parent[x] = find(parent, parent[x]);
  }
  return parent[x];
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值