含有相同数量的 0 和 1 的最长连续子数组


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


解题思路

使用前缀和 + 哈希表的方式实现,由于「0 和 1 的数量相同」等价于「1 的数量减去 0 的数量等于 0」,我们可以将数组中的 0 视作 −1,则原问题转换成「求最长的连续子数组,其元素和为 0」

假设子数组 newNums,为了计算 newNums 的元素和,我们需要先计算 nums 的前缀和。用 preNums[i] 表示 nums 从下标 0 到下标 i 的前缀和,则 newNums 从下标 j + 1 到下标 k(其中 j < k)的子数组的元素和为 preNums[k] - preNums[j],该子数组的长度为 k - j

当 preNums[k] - preNums[j] = 0 时,即得到一个长度为 k − j 的子数组元素和为 0,对应该子数组中有相同数量的 0 和 1

实现方面,维护一个变量 counter 存储 newNums 的前缀和,遍历数组 nums,当遇到元素 1 时将 counter 的值加 1,当遇到元素 0 时将 counter 的值减 1,遍历过程中使用哈希表存储每个前缀和第一次出现的下标

规定空的前缀的结束下标为 −1,由于空的前缀的元素和为 0,因此在遍历之前,首先在哈希表中存入键值对 (0,−1)。遍历过程中,对于每个下标 i,进行如下操作:

  • 如果 counter 的值在哈希表中已经存在,则取出 counter 在哈希表中对应的下标 preIndex,nums 从下标 preIndex + 1 到下标 i 的子数组中有相同数量的 0 和 1,该子数组的长度为 i − preIndex,使用该子数组的长度更新最长连续子数组的长度;
  • 如果 counter 的值在哈希表中不存在,则将当前余数和当前下标 i 的键值对存入哈希表中

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

class Solution {
    
    
    public int findMaxLength(int[] nums) {
    
    
        int counter = 0;
        int maxLength = 0;
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, -1);
        for(int i = 0; i < nums.length; i++) {
    
    
            if(nums[i] == 0) {
    
    
                counter--;
            } else {
    
    
                counter++;
            }
            if(map.containsKey(counter)) {
    
    
                int preSumLength = i - map.get(counter);
                maxLength = Math.max(maxLength, preSumLength);
            } else {
    
    
                map.put(counter, i);
            }
        }
        return maxLength;
    }
}

猜你喜欢

转载自blog.csdn.net/CSDN_handsome/article/details/117626821