Leecode 560 和爲K的子數組個數

題目說明:

給定一個整數數組和一個整數 k,你需要找到該數組中和爲 k 的連續的子數組的個數。

示例 1 :

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

說明 :
數組的長度爲 [1, 20,000]。
數組中元素的範圍是 [-1000, 1000] ,且整數 k 的範圍是 [-1e7, 1e7]

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/subarray-sum-equals-k

代碼:

方法1是hash 方法2是暴力枚舉

//hash
    public static int subarraySum(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        int sum = 0, res = 0;
        map.put(0, 1);
        for(int i = 0; i < nums.length; i++){
            sum += nums[i];
            if(map.containsKey(sum - k))
                res += map.get(sum - k);
            map.put(sum, map.getOrDefault(sum, 0) + 1);
        }
        return res;
    }

    //暴力枚舉
    public static int subarraySumDemo(int[] nums, int k){
        int res = 0;
        for(int i = 0; i < nums.length; i++) {
            int sum = 0;
            if(nums[i] == k)
                res++;
            sum += nums[i];
            for(int j = i + 1; j < nums.length; j++){
                sum += nums[j];
                if(sum == k)
                    res++;
            }
        }
        return res;
    }

思路

  • 暴力枚舉
    一般最簡單的想法就是暴力枚舉,兩個for循環,挨着計算每一個子數組的和 判斷是否等於K。
    這個辦法剛開始我想這是否能夠優化,就是提前跳出循環:
    ① 當前nums[i]已經大於K了,跳出循環
    ②當前sum + nums[j] > k 跳出循環,不用再計算後面
    但是這些都必須建立在前提爲數組元素全部非負,而題目給出的數組是沒有限定非負的,所以就沒辦法實現。

  • hash
    map存儲數組nums挨個的sum,和sum出現的個數
    數組前n項的和爲 ** sum(n) = nums[0] + …… + nums[n];**
    數組第n項到第j項的和爲 ** sum(n~j) = nums[n] + …… + nums[j]; **
    其實計算前n項的和是否等於K,比較容易。 難的就是如何不忽略那種 sum(n~j) == k 的情況
    那麼就需要去計算sum(n~j)
    sum(n~j) = sum(j) - sum(n)
    假設 sum(n~j) == k
    那麼式子就可以變換爲:
    k = sum(j) - sum(n);
    sum(j) - k = sum(n)
    也就是說 map裏面 判斷當前的sum - k 的值是否已經存在於map中,如果存在即代表 sum(n~j) == k
    此時計數器 +1
    不得不說 這個方法確實不錯 只需要O(n)的時間複雜度,屬實牛逼嗷
    剛開始沒想出來 算法這方面還是得加強,有些時候還是要想着數學的方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章