LeetCode——523. 连续的子数组和(Continuous Subarray Sum)[中等]——分析及代码(Java)

LeetCode——523. 连续的子数组和[Continuous Subarray Sum][中等]——分析及代码[Java]

  • 一、题目
  • 二、分析及代码
    • 1. 前缀和 + 哈希表
      • (1)思路
      • (2)代码
      • (3)结果
  • 三、其他

一、题目

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

示例 1:

输入:[23,2,4,6,7], k = 6
输出:True
解释:[2,4] 是一个大小为 2 的子数组,并且和为 6。

示例 2:

输入:[23,2,6,4,7], k = 6
输出:True
解释:[23,2,6,4,7]是大小为 5 的子数组,并且和为 42。

说明:

  • 数组的长度不会超过 10,000 。
  • 你可以认为所有数字总和在 32 位有符号整数范围内。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/continuous-subarray-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、分析及代码

1. 前缀和 + 哈希表

(1)思路

设计一个前缀和数组 preSum, 其中 preSum[i] 表示 nums 中 [0, i) 区间内的前缀和,则 nums 中子数组 [i, j] 的总和可表示为 preSum[j + 1] - preSum[i]。
如果 nums 子数组 [i, j] 总和为 k 的倍数,则 (preSum[j + 1] - preSum[i]) % k == 0,即 preSum[j + 1] % k == preSum[i] % k,结合这一特点,可通过寻找 preSum 数组中是否存在对 k 取模后余数相同的值,判断该子区间是否存在。
题目要求子区间大小至少为 2,可进一步结合哈希表,存储各余数最早出现时的下标。

(2)代码

class Solution {
    public boolean checkSubarraySum(int[] nums, int k) {
        int n = nums.length;

        //求解nums各位置的前缀和
        int[] preSum = new int[n + 1];
        Arrays.fill(preSum, 0);
        for (int i = 0; i < n; i++)
            preSum[i + 1] = preSum[i] + nums[i];
        
        //结合哈希表确定是否存在总和为k的倍数的区间
        Map<Integer, Integer> map = new HashMap<>();//key: 前缀和对k取模; value: 第一次出现key时的下标位置
        for (int i = 0; i <= n; i++) {
            int m = preSum[i] % k;
            if (map.containsKey(m)) {
                if (i - map.get(m) > 1)//子数组大小至少为2
                    return true;
            } else
                map.put(m, i);
        }
        return false;
    }
}

(3)结果

执行用时 :17 ms,在所有 Java 提交中击败了 79.21% 的用户;
内存消耗 :52.9 MB,在所有 Java 提交中击败了 51.93% 的用户。

三、其他

暂无。

你可能感兴趣的:(数据结构与算法,LeetCode,Java,题解)