continuous sum equals K(follow up问了可以负数和0,最后又follow up 算最大长度)
nums = [1,2,3,4,5,4], k = 9, 求有多少个符合的subarray
分析:当数组只有正数时双指针的方法为最优,时间2*N,空间1,HashSet的方法也可以解,时间N,空间N
解法一:双指针(数组仅有正数,否则指针无法正确移动)
//两个指针从头开始,当sum小于k的时候,移动右指针,当sum大于k的时候,证明从左指针开始的subarray一定没有答案了,因此移动左指针。依次下去直到遍历结束。
//能写for循环就不要写while循环,因为while循环里的index一旦改变,就要重新判断一次,否则会导致indexOutOfBoundary!!!
//尽量写for循环!!!
public static int subarraySum(int[] nums, int k) {
if (nums.length == 0) return 0;
int left = 0;
int right = 0;
int sum = nums[0];
int res = 0;
while (right < nums.length) {
if (sum >= k) {
if (sum == k) res++;
sum = sum - nums[left];
left++;
if (left > right) {
right = left;
if (right == nums.length) break;
sum = sum + nums[left];
}
} else {
right++;
if (right == nums.length) break;
sum = sum + nums[right];
}
}
return res;
}
Lin主任的写法(用了for循环):
private static int subarraySum(int[] n, int t ) {
int re = 0;
int l = 0;
int now = 0;
for(int r = 0; r < n.length; r++) {
now += n[r];
while(now >= t && l < r) {
if(now == t)re++;
now -= n[l];
l++;
}
if(now == t)re++;
}
return re;
}
解法二:只是正数的话,HashSet就足够了。
public int subarraySum(int[] nums, int k) {
if (nums.length == 0 || k<= 0) return 0;
HashSet<Integer> set = new HashSet<>();
int sum = 0;
set.add(0);
int res = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
set.add(sum);
if (set.contains(sum - k)) {
res++;
}
}
return res;
}
Follow up 1: 如果可以有负数和0
//需要用HashMap来存sum值的个数,因为有了负数和0会导致当前sum值和前面一样。
public int subarraySum(int[] nums, int k) {
if (nums.length == 0) return 0;
HashMap<Integer, Integer> set = new HashMap<>();
int sum = 0;
set.put(0, 1);
int res = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
if (set.containsKey(sum - k)) {
res = res + set.get(sum - k);
}
if (set.containsKey(sum)) {
set.put(sum, set.get(sum) + 1);
} else {
set.put(sum, 1);
}
}
return res;
}
Follow up 2: 返回最大长度
//由于需要返回最大长度,因此我们需要存储index, 所以hashmap里的value不存个数,而是存一个list of integer, 把所有的index存进来,这样遇到符合的,返回list里的第一个即可,此方法也可用于返回所有符合要求的subarray.
//注意按照定义来写类型,
public int subarraySum(int[] nums, int k) {
if (nums.length == 0) return 0;
HashMap<Integer, List<Integer>> set = new HashMap<>();
int sum = 0;
List<Integer> list = new ArrayList<>();
list.add(-1);
set.put(0, list);
int res = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
if (set.containsKey(sum - k)) {
res = Math.max(res, i - set.get(sum-k).get(0));
}
if (set.containsKey(sum)) {
set.get(sum).add(i);
} else {
List<Integer> list = new ArrayList<>();
list.add(i);
set.put(sum, list);
}
}
return res;
}
以下这种方法也行,只需要存第一个integer就够了
public int maxSubArrayLen(int[] n, int k) {
Map<Integer, Integer> m = new HashMap<>();
m.put(0, -1);
int sum = 0;
int max = 0;
for (int i = 0; i < n.length; i++) {
sum+=n[i];
if(m.containsKey(sum-k) && (i - m.get(sum-k))>max) max = i - m.get(sum-k);
if(!m.containsKey(sum))m.put(sum, i);
}
return max;
}