523. 连续的子数组和

454 阅读1分钟

523. 连续的子数组和前缀和hash

给定一个包含 非负数 的数组和一个目标 整数 k ,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,且总和为 k 的倍数,即总和为 n * k ,其中 n 也是一个整数。

7 3 6 6 6 6 6 6: 6

10 16 22 4 4 4

用数学分析:

x1%6 = t; x2%6 = t; 可得出:(x1-x2)%6 = 0;

只需要找出俩个余数相等的索引,并且间隔长度超2即可。

存入map: {key:sum % k, value:i}

考虑情况:k若为0

Hash写法 java:

import java.util.HashMap;
import java.util.Map;

public class Solution {

    public boolean checkSubarraySum(int[] nums, int k) {
        int sum = 0;

        // key:区间 [0..i] 里所有元素的和 % k
        // value:下标 i
        Map<Integer, Integer> map = new HashMap<>();
        // 理解初始化的意义
        map.put(0, -1);
        int len = nums.length;
        for (int i = 0; i < len; i++) {
            sum += nums[i];
            if (k != 0) {
                sum = sum % k;
            }
            //其他参考 int key = k == 0 ? preSum : preSum % k;map.containsKey(key)
            if (map.containsKey(sum)) {
                if (i - map.get(sum) > 1) {
                    return true;
                }
            } else {
                map.put(sum, i);
            }

        }
        return false;
    }
}

复杂度分析

  • 时间复杂度:O(N)O(N),仅需要遍历输入数组一遍;
  • 空间复杂度:O(min(n,k))O(min(n,k))。哈希表最多包含 min(n,k)min(n,k) 个不同的元素。

前缀和写法 java:

public class Solution {
    public boolean checkSubarraySum(int[] nums, int k) {
        int len = nums.length;
        int[] preSum = new int[len + 1];
        preSum[0] = 0;
        for(int i = 0; i < len; i++) {
            preSum[i + 1] = preSum[i] + nums[i];
        }
        for(int left = 0; left < len - 1; left++) {
            for(int right = left + 1; right < len; right++) {
                int temp = preSum[right + 1] - preSum[left];
                if (temp == k || (k != 0 && temp % k == 0)) {
                    return true;
                }
            }
        }
        return false;
    }
}