LeetCode——523. 连续的子数组和[Continuous Subarray Sum][中等]——分析及代码[Java]
一、题目
给定一个包含 非负数 的数组和一个目标 整数 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% 的用户。
三、其他
暂无。