【Leetcode算法题】525. 连续数组

By Long Luo

525. 连续数组题目如下:

  1. 连续数组
    给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。

示例 1:
输入: nums = [0,1]
输出: 2
说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。

示例 2:
输入: nums = [0,1,0]
输出: 2
说明: [0, 1] (或 [1, 0]) 是具有相同数量0和1的最长连续子数组。

提示:
1 <= nums.length <= 10^5
nums[i] 不是 0 就是 1

方法一:暴力遍历

思路与算法:

首先想到的方法是暴力遍历,第一层循环,索引i0n,第二层循环则是计算到i+1n01的数量,如果相等,则更新最大长度\textit{maxLength}

代码如下所示:

public int findMaxLength(int[] nums) {
    if (nums == null || nums.length <= 1) {
        return 0;
    }

    int ans = 0;
    int n = nums.length;
    int zeroNum = 0;
    int oneNum = 0;
    for (int i = 0; i < n; i++) {
        zeroNum = 0;
        oneNum = 0;
        if (nums[i] == 0) {
            zeroNum++;
        } else {
            oneNum++;
        }

        for (int j = i + 1; j < n; j++) {
            if (nums[j] == 0) {
                zeroNum++;
            } else {
                oneNum++;
            }

            if (zeroNum == oneNum) {
                ans = Math.max(ans, 2 * zeroNum);
            }
        }
    }

    return ans;
}

复杂度分析:

  • 时间复杂度:O(N^2),其中N是数组\textit{nums}的长度。
  • 空间复杂度:O(1),多了2个记录01的数量变量。

方法二:哈希表 + 前缀和

思路与算法:

方法一的暴力还是太慢了,涉及到连续的数组元素,第一想到的是可以使用前缀和。如果i<j,prefix[j]-prefix[j]等于j - i / 2的,则认为i到j之间0和1的个数是一样的。我们可以先计算出数组的前缀和数组,然后再遍历一遍,求出最长的子数组。

实际上这种思路还有一个更巧妙的方法:那就是将0视作-1,则原问题转换成“求最长的连续子数组,其元素和为0”。

实现方面,不需要创建数组\textit{newNums}\textit{prefixSums},只需要维护一个变量\textit{counter}存储\textit{newNums}的前缀和即可。具体做法是,遍历数组\textit{nums},当遇到元素1时将\textit{counter}的值加1,当遇到元素0时将\textit{counter}的值减1,遍历过程中使用哈希表存储每个前缀和第一次出现的下标。

如果\textit{counter}的值在哈希表中已经存在,则取出\textit{counter}在哈希表中对应的下标\textit{prevIndex}\textit{nums}从下标\textit{prevIndex}+1到下标i的子数组中有相同数量的01,该子数组的长度为i-\textit{prevIndex},使用该子数组的长度更新最长连续子数组的长度;

如果\textit{counter}的值在哈希表中不存在,则将当前余数和当前下标i的键值对存入哈希表中。

由于哈希表存储的是\textit{counter}的每个取值第一次出现的下标,因此当遇到重复的前缀和时,根据当前下标和哈希表中存储的下标计算得到的子数组长度是以当前下标结尾的子数组中满足有相同数量的01的最长子数组的长度。遍历结束时,即可得到\textit{nums}中的有相同数量的01的最长子数组的长度。

代码如下所示:

public int findMaxLength(int[] nums) {
    if (nums == null || nums.length <= 1) {
        return 0;
    }

    int ans = 0;
    int n = nums.length;
    Map<Integer, Integer> map = new HashMap<>();
    int sum = 0;
    map.put(0, -1);
    for (int i = 0; i < n; i++) {
        if (nums[i] == 1) {
            sum++;
        } else {
            sum--;
        }
        if (map.containsKey(sum)) {
            int prevIndex = map.get(sum);
            ans = Math.max(ans, i - prevIndex);
        } else {
            map.put(sum, i);
        }
    }

    return ans;
}

复杂度分析:

  • 时间复杂度:O(N),其中N是数组\textit{nums}的长度。
  • 空间复杂度:O(N),其中N是数组\textit{nums}的长度。
    空间复杂度主要取决于哈希表,哈希表中存储的不同的\textit{counter}的值不超过N个。

原文链接:【Leetcode算法题】525. 连续数组

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容