1. 程式人生 > 實用技巧 >力扣-560-和為K的子陣列

力扣-560-和為K的子陣列

給定一個整數陣列和一個整數k你需要找到該陣列中和為k的連續的子陣列的個數。

輸入:nums = [1,1,1], k = 2
輸出: 2 , [1,1] 與 [1,1] 為兩種不同的情況。

方法一、字首和(不優化)
定義pre[i]為[0..i]裡所有數的和,即字首和。you遞推關係得到:  
      pre[i] = pre[i-1]+nums[i];

那有了字首和,我們就能很方便地表示[j..i]這個子陣列的和,時間複雜度為O(1),表示如下:
      sum[j..i] = pre[i] - pre[i-1];

那想要找到滿足和為k的子陣列的個數,實際上就是求:
      if(pre[i] - pre[j-1]==k){ res++; }

我們可以列舉i,找到滿足pre[j] = pre[i]-k的j的個數即可,通過上述分析,我們可以得到下述程式碼:

class Solution {
    public int subarraySum(int[] nums, int k) {
        int len = nums.length;
        int[] pre = new int[len+1];
        
        for(int i = 1; i <= len; i++) {
            if(i==1) {
                pre[i] = nums[i-1];
            }else {
                pre[i] = pre[i-1] + nums[i-1];
            }
        }
        
        
int res = 0; for(int i=0; i<=len; i++) { for(int j=0; j<i; j++) { if((pre[i]-pre[j])==k) { res+=1; } } } return res; } }

方法二、字首和+HashMap優化

從方法一,我們可以看到,每次列舉i後,我們都要遍歷i之前的j,看是否滿足:

              pre[j] == pre[i] - k

所以我們可以考慮用Map,(鍵,值)= (pre[i], 出現的次數)。在從左到右列舉i的過程中,同時更新hashmap,那麼以i結尾的答案hashmap[pre[i] - k],就能在O(1)的時間內得到,最後將列舉所有i的結果累加即可,產生最終的答案。

需要注意的是,從左往右計算hashmap[pre[i] - k],裡面記錄的pre[j]的下表範圍是0<=j<=i。又因為pre[i]的計算只與前一項的答案有關,因此就不用建立pre[]陣列,直接用pre變數記錄即可。程式碼如下:

class Solution {
    public int subarraySum(int[] nums, int k) {
        int ans = 0, presum = 0;
        Map<Integer, Integer> hashmap = new HashMap<Integer, Integer>();
        
        hashmap.put(0, 1);
        
        for(int i=0; i<nums.length; i++) {
            presum+=nums[i];
            if(hashmap.containsKey(presum - k)) {
                ans += hashmap.get(presum-k);
            }
            hashmap.put(presum, hashmap.getOrDefault(presum, 0) + 1);
        }
        return ans;
    }