【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 位置上的前缀数组和。

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

目录
相关文章
|
5月前
leetcode-475:供暖器
leetcode-475:供暖器
39 0
|
5月前
|
Java
leetcode-474:一和零
leetcode-474:一和零
37 0
|
存储
leetcode:53.最大字序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
46 0
leetcode 283 移动零
leetcode 283 移动零
51 0
|
算法
LeetCode——944. 删列造序
LeetCode——944. 删列造序
102 0
LeetCode 283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
83 0
|
存储 算法
leetcode第49题
时间复杂度:两层 for 循环,再加上比较字符串,如果字符串最长为 K,总的时间复杂度就是 O(n²K)。 空间复杂度:O(NK),用来存储结果。 解法一算是比较通用的解法,不管字符串里边是大写字母,小写字母,数字,都可以用这个算法解决。这道题的话,题目告诉我们字符串中只有小写字母,针对这个限制,我们可以再用一些针对性强的算法。 下边的算法本质是,我们只要把一类的字符串用某一种方法唯一的映射到同一个位置就可以。
147 0
leetcode第49题
|
算法
leetcode第42题
也就是红色区域中的水, 数组是 height = [ 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 ] 。 原则是高度小于 2,temp ++,高度大于等于 2,ans = ans + temp,temp = 0。 temp 初始化为 0 ,ans 此时等于 2。 height [ 0 ] 等于 0 < 2,不更新。 height [ 1 ] 等于 1 < 2,不更新。 height [ 2 ] 等于 0 < 2, 不更新。 height [ 3 ] 等于 2 >= 2, 开始更新 height [ 4 ] 等于 1 < 2,temp = temp + 1 = 1。 h
leetcode第42题
|
存储 算法
leetcode第43题
个位乘个位,得出一个数,然后个位乘十位,全部乘完以后,就再用十位乘以各个位。然后百位乘以各个位,最后将每次得出的数相加。十位的结果要补 1 个 0 ,百位的结果要补两个 0 。相加的话我们可以直接用之前的大数相加。直接看代码吧。
leetcode第43题
leetcode第34题
从左向右遍历,一旦出现等于 target 的值就结束,保存当前下标。如果从左到右没有找到 target,那么就直接返回 [ -1 , -1 ] 就可以了,因为从左到右没找到,那么从右到左也一定不会找到的。如果找到了,然后再从右到左遍历,一旦出现等于 target 的值就结束,保存当前下标。 时间复杂度是 O(n)并不满足题意,但可以了解下这个思路,从左到右,从右到左之前也遇到过。
leetcode第34题