给定一个非负整数数组array和一个整数k,验证array中是否有长度大于1的子串,使该子串的和等于k的整数倍。如数组array = [23, 2, 4, 6, 7],k = 6,因为2 + 4 = 6,所以返回true。
方法一:按照典型的动态规划方法,对数组进行两层遍历。该方法时间复杂度为O(n^2)。
public boolean checkSubarraySum(int[] nums, int k) {
if(nums.length < 2) return false;
int[] dp = new int[nums.length];
for(int i = 0; i < nums.length; i++) {
dp[i] = nums[i];
}
for(int l = 1; l < nums.length; l++) { //长度
for(int i = 0; i + l < nums.length; i++) { //子串起点
int j = i + l; //子串终点
dp[i] += nums[j];
if( k == 0 && dp[i] == 0 || k != 0 && dp[i] % k == 0)
return true;
}
}
return false;
}
方法二:记录一个当前数组和对 k 的余数,如果在访问元素 j 时,当前余数在前面的某个元素 i 中出现过,说明从 i 到 j 的子串和为 k 的整数倍。该方法只需遍历数组一次,时间复杂度为O(n)。
public boolean checkSubarraySum(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<Integer, Integer>(){{put(0,-1);}};
int runningSum = 0;
for (int i=0;i<nums.length;i++) {
runningSum += nums[i];
if (k != 0) runningSum %= k;
Integer prev = map.get(runningSum);
if (prev != null) { //prev存在,说明runningSum在前面的元素中出现过
if (i - prev > 1) return true;
}
else map.put(runningSum, i);
}
return false;
}