題目說明:
給定一個整數數組和一個整數 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)的時間複雜度,屬實牛逼嗷
剛開始沒想出來 算法這方面還是得加強,有些時候還是要想着數學的方法