【LeetCode】560. 和為K的子陣列
阿新 • • 發佈:2021-07-17
560. 和為K的子陣列
知識點:陣列;字首和;
題目描述
給定一個整數陣列和一個整數 k,你需要找到該陣列中和為 k 的連續的子陣列的個數。
示例
輸入:nums = [1,1,1], k = 2
輸出: 2 , [1,1] 與 [1,1] 為兩種不同的情況。
解法一:暴力法
直接以每個元素為首開始;
class Solution { public int subarraySum(int[] nums, int k) { int sum = 0; int count = 0; for(int i = 0; i < nums.length; i++){ //依次以元素開始; for(int j = i; j < nums.length; i++){ sum += nums[j]; if(sum == k) count++; } sum = 0; //一次結束後歸零; } return count; } }
時間複雜度:O(N^N);
解法二:字首和
字首和是很常見的一種解題思路,其含義就是高中學過的數列的前n項和;
所以如果我們要求哪個子序列和為k的話,就可以轉化為求字首和陣列中哪兩個的值相減等於k。這熟悉嗎?對啊,這不就是兩數之和那個題嗎?還記得怎麼做的嗎?就是用雜湊表存,key和value分別就是數值和其索引下標,為什麼存索引下標,因為那個題讓我們求的就是索引下標。那類比一下,這個題呢,這個題是讓我們幹嘛,是求有幾項和,那我們的value就是對應的前n項和為某個值的有幾個,這樣減出來的子序列就有幾個;
// 字首和沒有優化; class Solution { public int subarraySum(int[] nums, int k) { int count = 0; int[] premsum = new int[nums.length+1]; //比原陣列長一位,第一位置為0;這樣才能把nums[1]包括; for(int i = 0; i < nums.length; i++){ //構建字首和陣列; premsum[i+1] = premsum[i] + nums[i]; } for(int i = 0; i < premsum.length-1; i++){ for(int j = i+1; j < premsum.length; j++){ if(premsum[j] - premsum[i] == k) count++; } } return count; } }
時間複雜度:依然是O(N^N);
// 字首和+雜湊表; class Solution { public int subarraySum(int[] nums, int k) { Map<Integer,Integer> map = new HashMap<>(); map.put(0,1); int premsum = 0; int count = 0; for(int i = 0; i < nums.length; i++){ premsum += nums[i]; //字首和; if(map.containsKey(premsum-k)) count += map.get(premsum-k); map.put(premsum, map.getOrDefault(premsum, 0)+1); //字首和為不同值的有幾次; } return count; } }
時間複雜度:O(N);
體會
字首和是一種很常用的思想,要對觸發它的條件敏感 連續子陣列+和,也就是用在哪一種題型裡;
其次,雜湊表也要敏感,比如在一個題目中有兩數之和,那就要去用雜湊表,可以利用其containsKey函式檢索,從而少一次for迴圈;而雜湊表中value的值就由我們要獲得什麼決定,比如此題是獲得子陣列的個數,那value就是每個和的次數;比如我們要獲得子陣列的大小或者下標,那value就是元素的索引,對症下藥。
相關題目
1. 兩數之和
930. 和相同的二元子陣列
724. 尋找陣列的中心下標
1248. 統計「優美子陣列」
974. 和可被 K 整除的子陣列
523. 連續的子陣列和