雙指標之滑動視窗(長度最小的子陣列 和 和為s的連續正數序列)
雙指標之滑動視窗 (長度最小的子陣列;和為s的連續正數序列)
1, 什麼時候使用? (與子陣列/字串 有關的題目)~如果給了某個具體值的target,即用滑動視窗 不然就雙指標(一般做法,左邊< 右邊,依據條件左邊和右邊都不斷靠近) |
滑動視窗:是雙指標的題目
找出一個數組中滿足一定條件的子陣列問題,字串也可以看成陣列。看到子陣列問題,就是DP回溯滑動視窗這三種之一
2,滑動視窗的通用框架 1:(例題:209_長度最小的子陣列)
(做題特點一:題目給定了具體的值target,這個target條件的可能彈性空間比較大了
【例如題目 要求某種情況下>= target】,而大於target的可能情況就會比較多了
* ① 先移動右指標確定視窗的大致可能範圍(在這大致可能範圍裡找到最優範圍),然後暫時固定住右指標,
* ② 在滿足條件(滿足target下):不斷的移動左指標,縮小視窗
* ③ 當不滿足target了,又開始移動右指標,然後。。。。。又確定下來視窗的大致可能範圍
(在這大致可能範圍裡找到最優範圍),然後暫時固定住右指標。。。
* 特點2,形式上的特點(左右指標移動的方向):是一開始左右指標,同方法移動)
public class 滑動視窗的通用框架 1{ public String slidingWindow(String s, String t) { // 起始的時候,都位於 0,同方向移動int left = 0; int right = 0; int sLen = s.length(); while (right < sLen) { char c = s.charAt(right); right++; //對狀態做修改 while ( 滿足某種條件 ) { //更新ans可能的地方之一 charc1 = s.charAt(left); left++; //對狀態做修改 } //更新ans可能的地方之二 } return 需要的結果變數; } }
例題:
package 陣列; /** * https://leetcode-cn.com/problems/minimum-size-subarray-sum/ * @author Huangyujun * * 注意細節:當找到滿足條件的視窗時,需要固定右邊界, * 逐漸移動左邊界(縮小視窗大小),直到視窗元素和不滿足要求,再改變右邊界。使用while迴圈縮小! * */ public class _209_長度最小的子陣列 { public int minSubArrayLen(int s, int[] nums) { int n = nums.length; if (nums == null || n == 0) return 0; int ans = Integer.MAX_VALUE; int left = 0, right = 0; int sum = 0; while (right < n) { sum += nums[right++]; while (sum >= s) { ans = Math.min(ans, right - left); sum -= nums[left++]; } } return ans == Integer.MAX_VALUE ? 0 : ans; } }
3,滑動視窗的通用框架 2:(例題:57_和為s的連續正數序列)
做題特點 一:題目給定了具體的值target,這個target條件的可能彈性空間唯一了
【例如題目 要求某種情況下= target】,而等於target的可能情況在“暫時固定下的範圍視窗中情況就是固定下該視窗呀”
* ① == target,這種直接通過判斷找視窗範圍,找到一個固定視窗範圍後,移動左邊指標(達到整體視窗向前移動)
去找下一個固定視窗範圍
* 這類題:直接分:①== target,② < target ,③ > target 來找合適的固定視窗範圍
public class 滑動視窗的通用框架 2{ public String slidingWindow(int target) { // 起始的時候,同方向移動 int left = 1; int right = 2; while (l < r) { 更新ans if( ans == target){ //需要的結果,得到了一個 l++; }else if(ans < target){ //比target小,右指標往前移動,擴大範圍 r++; }else{ //比target大,左指標往前移動,縮小範圍 l++; } } return 需要的結果變數; } }
例題:
package 陣列; /** * https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/ */ import java.util.ArrayList; import java.util.List; public class _57_和為s的連續正數序列 { /** * 細節:正數 思路: 1、雙指標技術,就是相當於有一個視窗,視窗的左右兩邊就是兩個指標 2、根據視窗內值之和來確定視窗的位置和寬度。 */ public int[][] findContinuousSequence(int target) { List<int[]> vec = new ArrayList<int[]>(); int l = 1, r = 2; while(l < r) { //求和公式 int sum = (l + r) * (r - l + 1) / 2; if (sum == target) { int[] res = new int[r - l + 1]; for (int i = l; i <= r; ++i) { res[i - l] = i; } vec.add(res); l++; //找到之後,左邊指標往前挪動,意味著整個視窗往前挪動 } else if (sum < target) { r++; } else { l++; } } return vec.toArray(new int[vec.size()][]); } }
✿ 沒給某個具體值的target,使用一般雙指標思路(一般做法,左邊< 右邊,依據條件左邊和右邊都不斷靠近):
例題:(盛最多水的容器)
// https://leetcode-cn.com/problems/container-with-most-water/
//正解:雙指標法 public class Solution { public int maxArea(int[] height) { int l = 0, r = height.length - 1; int ans = 0; while (l < r) { //面積公式 高:最小的 【左柱子,右柱子】 int area = Math.min(height[l], height[r]) * (r - l); ans = Math.max(ans, area); // 需要找小的:(目的:去獲取那個小柱子中的最大值) if (height[l] <= height[r]) { ++l; } else { --r; } } return ans; } }