Algorithm/src/main/java/substring/CheckSubarraySum.java
2025-03-18 09:09:22 +08:00

80 lines
2.8 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package substring;
import java.util.HashMap;
/**
* 题目523. 连续的子数组和 (checkSubarraySum)
* 描述:给你一个整数数组 nums 和一个整数 k ,如果 nums 有一个 好的子数组 返回 true ,否则返回 false
一个 好的子数组 是:
长度 至少为 2 ,且
* 子数组元素总和为 k 的倍数。
* 注意:
* 子数组 是数组中 连续 的部分。
* 如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称 x 是 k 的一个倍数。0 始终 视为 k 的一个倍数。
*
* 链接https://leetcode.cn/problems/continuous-subarray-sum/
示例 1
输入nums = [23,2,4,6,7], k = 6
输出true
解释:[2,4] 是一个大小为 2 的子数组,并且和为 6 。
示例 2
输入nums = [23,2,6,4,7], k = 6
输出true
解释:[23, 2, 6, 4, 7] 是大小为 5 的子数组,并且和为 42 。
42 是 6 的倍数,因为 42 = 7 * 6 且 7 是一个整数。
示例 3
输入nums = [23,2,6,4,7], k = 13
输出false
*/
//需重做
//本题不一样的地方是无需统计个数,故哈希表中键值可以存索引。
public class CheckSubarraySum {
//枚举法超时
public boolean checkSubarraySum1(int[] nums, int k) {
for (int left = 0; left < nums.length; left++) {
int tpsum=nums[left];
for (int right = left+1; right < nums.length; right++) {
tpsum+=nums[right];
if(tpsum%k==0)
return true;
}
}
return false;
}
//前缀和 这题需要判断子数组和是否为 k 的倍数,因此我们关心的是前缀和对 k 取余后的值是否相等
public boolean checkSubarraySum(int[] nums, int k) {
// 特殊情况k == 0 的处理,寻找连续和为 0 的子数组
if (k == 0) {
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i] == 0 && nums[i+1] == 0) {
return true;
}
}
return false;
}
// 哈希表存储前缀和 mod k 的余数及其第一次出现的下标
HashMap<Integer, Integer> modMap = new HashMap<>();
modMap.put(0, -1); // 余数为0时将下标设为-1方便处理从数组开头开始的情况
int prefixSum = 0;
for (int i = 0; i < nums.length; i++) {
prefixSum += nums[i];
int mod = prefixSum % k;
// 如果这个余数之前出现过则当前下标和之前下标之差至少大于1
if (modMap.containsKey(mod)) {
if (i - modMap.get(mod) > 1) {
return true;
}
} else {
// 记录第一次出现该余数的下标
modMap.put(mod, i);
}
}
return false;
}
}