209 長度最小的子數組
https://leetcode-cn.com/problems/minimum-size-subarray-sum/submissions/
首先是滑動窗口的思路,我感覺這種尋找滿足某個條件的連續的子集,如這里的數組,可能還會在字符串里用到。
但這題卡了我很久的是邊界條件,下面這段代碼,當循環退出的時候,right的值是沒有被加到sum里的,所以right指向的位置是在sum數組的后面一個,所以最后計算結果的時候不是right-left+1,而是right-left,原因就是right在sum后面。
while (sum<s && right<nums.length){ sum+=nums[right]; right++; }
其次是初始條件如何設置,我一開是設置的left=right=0,這么設置是可以的,但是我把sum設置為了nums[0],這樣就有問題了,因為循環里面的時候sum+=nums[0],如果開頭sum=nums[0]這樣同一個nums[0]加了兩次。
class Solution { public int minSubArrayLen(int s, int[] nums) { if(nums.length==0){ return 0; } int left=0; int right = 0; int sum=0; int result = Integer.MAX_VALUE; while (left<=right && right<nums.length){ while (sum<s && right<nums.length){ sum+=nums[right]; right++; } while (sum>=s && left<right&& left<nums.length){ result = (result>(right-left))?right-left:result; sum-=nums[left]; left++; } } return result==Integer.MAX_VALUE?0:result; } }
219 存在重復元素2
https://leetcode-cn.com/problems/contains-duplicate-ii/
要求從長度為k的子元素串,變成了長度最大為k,其實本質上是一樣的。從索引為0的元素開始,檢查該元素長度為k的窗口是否滿足條件,如果滿足則返回,不滿足則繼續。在這一題中我想到了一個小小的優化,我之前的做法是先根據窗口的長度判斷i的最大值,即nums.length-i-k,但我發現這樣沒有必要,且不符合題目中要求的最大為k。所以我把i是否越界放到j的循環里判斷,用j<nums.length來避免越界。
class Solution { public boolean containsNearbyDuplicate(int[] nums, int k) { for (int i=0;i<nums.length;i++){ //在長度為k的區間內檢查是否能找到與i相等的點 for (int j=i+1;j<=i+k && j<nums.length;j++){ if (nums[j]==nums[i]){ return true; } } } return false; } }
除此之外還有一種優化手法,用空間換時間,用一個HashMap存儲窗口里的數值,如果每次滑動的時候刪除一個數值並加入一個新的數值。最終的提交結果是優於上一種方法。
- 首先窗口的長度為k+1,因為要求窗口里的元素索引之差為k。所以寫和滑動窗口有關的題目第一步計算出窗口的長度
- 其次從窗口的左端遍歷窗口的時候要在循環條件里加上不越界的判斷,即第一個循環的i<nums.length
class Solution { public boolean containsNearbyDuplicate(int[] nums, int k) { HashSet<Object> set = new HashSet<>(); //從0開始的前k個元素放進去 for (int i=0;i<k+1&&i<nums.length;i++){ if (!set.add(nums[i])){ return true; } } int i=0; for (int j=k+1;j<nums.length;j++){ set.remove(nums[i]); if (!set.add(nums[j])){ return true; } i++; } return false; } }