1. 程式人生 > 其它 >雙指標之滑動視窗(長度最小的子陣列 和 和為s的連續正數序列)

雙指標之滑動視窗(長度最小的子陣列 和 和為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可能的地方之一 char
c1 = 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; } }