1. 程式人生 > >Subarray Sum Equals K及其follow up

Subarray Sum Equals K及其follow up

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;
 }