js解leetcode(43)-中等

1.砖墙

题目:

你的面前有一堵矩形的、由多行砖块组成的砖墙。 这些砖块高度相同但是宽度不同。你现在要画一条自顶向下的、穿过最少砖块的垂线。

砖墙由行的列表表示。 每一行都是一个代表从左至右每块砖的宽度的整数列表。

如果你画的线只是从砖块的边缘经过,就不算穿过这块砖。你需要找出怎样画才能使这条线穿过的砖块数量最少,并且返回穿过的砖块数量。

你不能沿着墙的两个垂直边缘之一画线,这样显然是没有穿过一块砖的。

思路:遍历每一行,记录缝隙所在的位置及出现的次数,穿过的砖块最少,就是缝隙最多。所以找到最多的缝隙即可

时间复杂度O(n),空间复杂度O(m),n是砖块总数,m是宽度

/**
 * @param {number[][]} wall
 * @return {number}
 */
var leastBricks = function(wall) {
  const map = new Map();
  let rowSum = 0;
  for (const row of wall) {
    let sum = 0;
    for (const item of row) {
      sum += item;
      map.set(sum, (map.get(sum) || 0) + 1);
    }
    rowSum = sum;
  }
  map.delete(rowSum);
  if (!map.size) return wall.length;
  return wall.length - Math.max(...map.values());
};

2.下一个更大元素

题目:给定一个32位正整数 n,你需要找到最小的32位整数,其与 中存在的位数完全相同,并且其值大于n。如果不存在这样的32位整数,则返回-1。

思路:这个和之前某题很像。下一个更大的元素,就是找到最后的升序部分,然后将大于该数字的第一个数字交换,剩下的数字降序排列

/**
 * @param {number} n
 * @return {number}
 */
var nextGreaterElement = function(n) {
  let s = `${n}`.split("");
  let i = s.length - 2;
  while (s[i] >= s[i + 1]) i--; // 从右开始,找第一个严格降序的数字
  if (i < 0) return -1; // 不存在,返回-1
  let j = s.length - 1;
  while (s[j] <= s[i]) j--; // 从右开始,找到第一个比上一步找到数字大的
  [s[i], s[j]] = [s[j], s[i]]; // 换位
  let res = parseInt(
    s.slice(0, i + 1).join("") +
      s
        .slice(i + 1)
        .reverse()
        .join("")
  ); // 反转右边
  return res >= 2 ** 31 - 1 ? -1 : res;
};

3.和为K的子数组

题目:给定一个整数数组和一个整数 k,你需要找到该数组中和为 的连续的子数组的个数。

思路:注意条件,数组的元素可能是负数,所以不能用双指针。

可以利用前缀和的思路,记录每一个元素对应的前缀和及出现次数。对于当前的元素,如果前缀和是sum,且sum-k存在,那么说明之前有和为k的连续子数组

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

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var subarraySum = function(nums, k) {
  const l = nums.length;
  let v = 0;
  let c = 0;
  const map = new Map();
  map.set(0, 1);
  for (let i = 0; i < l; i++) {
    v += nums[i];
    c += map.get(v - k) || 0;
    map.set(v, (map.get(v) || 0) + 1);
  }
  return c;
};

4.数组嵌套

题目:

索引从0开始长度为N的数组A,包含0到N - 1的所有整数。找到最大的集合S并返回其大小,其中 S[i] = {A[i], A[A[i]], A[A[A[i]]], ... }且遵守以下的规则。

假设选择索引为i的元素A[i]为S的第一个元素,S的下一个元素应该是A[A[i]],之后是A[A[A[i]]]... 以此类推,不断添加直到S出现重复的元素。

思路:把数字看成为若干个环,我们要找到长度最长的环。因为对于一个环,任意节点进入该环都是一样的,所以一个dfs,遍历每个元素,然后进入dfs,记录遍历过的节点,如果遇到遍历过的,就退出当前循环,更新环的长度

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


/**
 * @param {number[]} nums
 * @return {number}
 */
var arrayNesting = function(nums) {
  const l = nums.length;
  const dp = new Array(l).fill(false);
  let res = 0;
  for (let i = 0; i < l; i++) {
    let c = 0;
    let v = i;
    while (!dp[v]) {
      c++;
      dp[v]=true
      v = nums[v];
    }
    res = Math.max(res, c);
  }
  return res;
};

5.字符串的排列

思路:

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。

思路:因为是排列,所以记录当前字符串的每个字符的出现次数,然后依次比较每个字符的出现次数是否相等。为了节约空间,在遍历s2的时候,只修改首尾两端的字符的出现次数

时间复杂度O(mn),空间复杂度O(m),m是s1的长度,n是s2的长度

/**
 * @param {string} s1
 * @param {string} s2
 * @return {boolean}
 */
var checkInclusion = function(s1, s2) {
  const map = new Map();
  const l = s1.length;
  for (const s of s1) {
    map.set(s, (map.get(s) || 0) + 1);
  }
  const map2 = new Map();
  for (let i = 0; i < l; i++) {
    map2.set(s2[i], (map2.get(s2[i]) || 0) + 1);
  }
  let right = l - 1;
  const l2 = s2.length;
  const keys = map.keys();
  let flag = true;
  for (const key of keys) {
    if (map.get(key) !== map2.get(key)) {
      flag = false;
      break;
    }
  }
  if (flag) return true;
  while (right < l2) {
    right++;
    const keyLeft = s2[right - l];
    const keyRight = s2[right];
    map2.set(keyLeft, (map2.get(keyLeft) || 0) - 1);
    map2.set(keyRight, (map2.get(keyRight) || 0) + 1);
    let flag = true;
  const keys = map.keys();
    for (const key of keys) {
      if (map.get(key) !== map2.get(key)) {
        flag = false;
        break;
      }
    }
    if (flag) return true;
  }
  return false;
};

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值