【LeetCode】这么简单的题,豆编又不会!

简介: 【LeetCode】这么简单的题,豆编又不会!

【LeetCode】这么简单的题,豆编又不会!

题目信息

525 - 连续数组

给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。
【 Tips 】
1 <= nums.length <= 10^5
nums[i] 不是 0 就是 1
=================================================
输入: nums = [0,1]
输出: 2
说明: [0, 1] 是具有相同数量0和1的最长连续子数组。
=================================================
输入: nums = [0,1,0]
输出: 2
说明: [0, 1] (或 [1, 0]) 是具有相同数量0和1的最长连续子数组。
=================================================
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/contiguous-array/

菜编思路

这个不难,这几天的题都是一样的类型,前缀数组和加上哈希表的套路。

  1. 这里可以做一次转化,把数组中的 0 换成 -1 去做处理,这样一个含有相同数量的 0 和 1 的连续数组的和就是 0
  2. 当连续数组和为 0 时,加上这个连续数组的前缀数组,和不加上这个连续数组的前缀数组,他们两个的和都是一样的。
  3. 我们记录前缀数组之和第一次出现的位置,然后再次遇到相同和时,求两次位置的差值

参考代码

public int findMaxLength(int[] nums) {
  int len = nums.length;
  if (len < 2)
    return 0;
  Map<Integer, Integer> map = new HashMap<>();
  // 位置 0 之前的前缀数组之和记做0,位置记做-1
  map.put(0, -1);
  // 前缀数组之和
  int sum = 0;
  // 记录最大的数组
  int max = 0;
  for (int i = 0; i < len; i++) {
    if (nums[i] == 1) {
      sum += 1;
    } else {
      sum += -1;
    }
    if (map.containsKey(sum)) {
      if (i - map.get(sum) > max)
        max = i - map.get(sum);
    } else {
      map.put(sum, i);
    }
  }
  return max;
}

这段代码理解起来很容易,思路很清晰,能看明白就好,今天的文章到此为止……


优雅升级

本来以为这样就结束了,豆编兴高采烈的提交完代码以后,发现运行速度处于下游水平,运行速度比最快的慢了近 5 倍……


这不行啊,然后就分析了一波上上上游水平的代码什么样子的。

public int findMaxLength(int[] nums) {
  // 数组长度
  int len = nums.length;
  // 定义一个长度时nums两倍的数组,存放前缀和对应的位置
  int[] sums = new int[2 * len + 1];
  // 最大的数组长度
  int max = 0;
  // 前缀数组的和
  int sum = 0;
  for (int i = 0; i < len; ++i) {
    // 计算前缀数组的和,0 替换成 -1处理
    sum += nums[i] == 0 ? -1 : 1;
    // 当sum为0时,表示这是个从头开始的数组,一定是当前最长的
    if (sum == 0)
      max = i + 1;
    // 位置数组的默认位置为0,当不是0时,这个和在之前出现过
    else if (sums[sum + len] != 0)
      max = Math.max(max, i - sums[sum + len] + 1);
    else
      // +1操作是为了避免位置为 0 时,sums数组存放 0,跟默认值冲突
      sums[sum + len] = i + 1;
  }
  return max;
}

这是一个空间换时间的算法,大体上还是一样的思想,只是细节上有些不一样。

这个解法有意思啊,这个两倍数组实现了哈希表的作用,存放位置信息,前缀和最小为 nums 长度的负值,这里不会出现数组越界。

前缀和为 0 时,出现的数组一定是当前最长的,避免了其他判断。

这里有一点容易出错的地方,就是i0 时,直接存放数组中,会跟默认值冲突,导致 else if 的判断失效,拿不到 0 位置上的前缀数组和。

最重要的是看懂了以后,要去自己实现一遍

目录
相关文章
|
9月前
leetcode-1219:黄金矿工
leetcode-1219:黄金矿工
92 0
|
9月前
|
Java
leetcode-474:一和零
leetcode-474:一和零
49 0
leetcode 827 最大人工岛
leetcode 827 最大人工岛
68 0
leetcode 827 最大人工岛
LeetCode 354. Russian Doll Envelopes
给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。 请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
88 0
LeetCode 354. Russian Doll Envelopes
|
算法 Java
一和零(LeetCode 474)
一和零(LeetCode 474)
105 0
leetcode第44题
时间复杂度:text 长度是 T,pattern 长度是 P,那么就是 O(TP)。 空间复杂度:O(TP)。 同样的,和第10题一样,可以优化空间复杂度。
108 0
leetcode第44题
|
存储
leetcode第57题
和上一道可以说是一个问题,只不过这个是给一个已经合并好的列表,然后给一个新的节点依据规则加入到合并好的列表。 解法一 对应 56 题的解法一,没看的话,可以先过去看一下。这个问题其实就是我们解法中的一个子问题没看的话,可以先过去看一下。这个问题其实就是我们解法中的一个子问题, 所以直接加过来就行了
117 0
leetcode第57题
|
存储 算法
leetcode第43题
个位乘个位,得出一个数,然后个位乘十位,全部乘完以后,就再用十位乘以各个位。然后百位乘以各个位,最后将每次得出的数相加。十位的结果要补 1 个 0 ,百位的结果要补两个 0 。相加的话我们可以直接用之前的大数相加。直接看代码吧。
102 0
leetcode第43题
|
算法
leetcode第45题
时间复杂度:O(n)。 空间复杂度:O(1)。 这里要注意一个细节,就是 for 循环中,i < nums.length - 1,少了末尾。因为开始的时候边界是第 0 个位置,steps 已经加 1 了。如下图,如果最后一步刚好跳到了末尾,此时 steps 其实不用加 1 了。如果是 i < nums.length,i 遍历到最后的时候,会进入 if 语句中,steps 会多加 1 。
132 0
leetcode第45题
leetcode第48题
将一个矩阵顺时针旋转 90 度,并且不使用额外的空间。大概属于找规律的题,没有什么一般的思路,观察就可以了。 解法一 可以先转置,然后把每列对称交换交换一下
100 0
leetcode第48题