鷹潭市城鄉(xiāng)建設局網(wǎng)站seo實戰(zhàn)密碼第四版
文章目錄
- 前言
- 什么是滑動窗口
- 1.長度最小的子數(shù)組
- 1.1 題目要求
- 1.2 做題思路
- 1.3 Java代碼實現(xiàn)
- 2.無重復字符的最長子串
- 2.1 題目要求
- 2.2 做題思路
- 2.3 Java代碼實現(xiàn)
- 3.最大連續(xù)1的個數(shù) III
- 3.1 題目要求
- 3.2 做題思路
- 3.3 Java代碼實現(xiàn)
- 4.將x減到0的最小操作數(shù)
- 4.1 題目要求
- 4.2 做題思路
- 4.3 Java代碼實現(xiàn)
- 5.水果成籃
- 5.1 題目要求
- 5.2 做題思路
- 5.3 Java代碼實現(xiàn)
- 6.找到字符串中所有字母異位詞
- 6.1 題目要求
- 6.2 做題思路
- 6.3 Java代碼實現(xiàn)
- 7.串聯(lián)所有單詞的子串
- 7.1 題目要求
- 7.2 做題思路
- 7.3 Java代碼實現(xiàn)
- 8.最小覆蓋字串
- 8.1 題目要求
- 8.2 做題思路
- 8.3 Java代碼實現(xiàn)
- 總結
前言
前面我們學習了什么是雙指針,今天我將為大家分享一種特殊的雙指針——滑動窗口,為什么說它是特殊的雙指針呢?因為它也是有兩個指針維護的,并且兩個指針的移動方向是相同的,就跟我們平時生活中的窗口一樣,兩條邊是往相同的方向移動的。
什么是滑動窗口
滑動窗口算法是一種用于解決數(shù)組或字符串相關問題的算法。它通過兩個指針維護的一個窗口,在窗口內(nèi)進行操作,并根據(jù)問題的要求移動窗口的起始位置或結束位置。
滑動窗口算法通常用于解決需要在連續(xù)子數(shù)組或子字符串中尋找最大值、最小值、滿足特定條件的值等問題。它的基本思想是通過調(diào)整窗口的大小和位置,以便在不重復計算的情況下,高效地處理問題。
滑動窗口算法的步驟如下:
- 初始化窗口的起始位置和結束位置。
- 根據(jù)問題的要求,移動窗口的起始位置或結束位置。
- 在每次移動窗口時,根據(jù)窗口內(nèi)的元素進行相應的操作,例如計算最大值、最小值、滿足特定條件的值等。
- 重復步驟2和步驟3,直到窗口移動到數(shù)組或字符串的末尾。
滑動窗口算法的時間復雜度通常為O(n),其中n為數(shù)組或字符串的長度。它通過避免重復計算,提高了問題的解決效率。
我們通過幾個例子來了解滑動窗口算法。
1.長度最小的子數(shù)組
https://leetcode.cn/problems/minimum-size-subarray-sum/
1.1 題目要求
給定一個含有 n 個正整數(shù)的數(shù)組和一個正整數(shù) target 。
找出該數(shù)組中滿足其和 ≥ target 的長度最小的 連續(xù)子數(shù)組 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其長度。如果不存在符合條件的子數(shù)組,返回 0 。
示例 1:
輸入:target = 7, nums = [2,3,1,2,4,3]
輸出:2
解釋:子數(shù)組 [4,3] 是該條件下的長度最小的子數(shù)組。
示例 2:
輸入:target = 4, nums = [1,4,4]
輸出:1
示例 3:
輸入:target = 11, nums = [1,1,1,1,1,1,1,1]
輸出:0
提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
class Solution {public int minSubArrayLen(int target, int[] nums) {}
}
1.2 做題思路
我們先來看看,如果使用暴力解法該怎么做。分別以每個數(shù)字開始,向后找 和>=target的子數(shù)組。
暴力解法是通過兩層循環(huán),i 從 0開始,j 從 i+1 開始遍歷整個數(shù)字,找到 和 >= target 的長度最小的子數(shù)組。并且這個和是每次循環(huán)都從 0 開始加的。
通過觀察每次循環(huán)找到的長度最小的子數(shù)組,我們可以發(fā)現(xiàn),left 指針和 right 指針都是向同一個方向向右移動的,暴力解法是每次循環(huán)結束之后 right 的位置就回到 left + 1 的位置,這樣就多了很多重復的不必要的計算。所以滑動窗口就是在這個暴力解法的基礎上進行優(yōu)化的,每次 right 的指向不進行返回,而是繼續(xù)向右滑動,那么為什么 right 的指向可以不用返回呢?因為每次循環(huán) left 的指向都會向右移動一位,而你要想找的長度最小的子數(shù)組的和 >= target,你的 right 就必須也是向右移動或者不移動,但是絕對不會是向左移動(在數(shù)組元素都是正數(shù)的情況下),這種就是滑動窗口的基本特征。
那么知道了使用滑動窗口這個算法的時候,我們來看看具體應該如何實現(xiàn)。定義一個 sum 變量,存儲每次進窗口之后這個窗口元素的和,并且這個sum 不是每一次都是逐個累加而是用之前的 sum 加上進窗口的這個元素,當 sum >= target 的時候,就需要進行出窗口的操作,并且在出窗口的時候,還需要判斷是否需要更新 ret 的值,繼續(xù)尋找后面的長度最小的子數(shù)組,每出一個元素,sum 就需要減去這個出去的數(shù),出窗口一直出到 sum < target,然后再進窗口,反復上面的操作,直到 right 到達數(shù)組末尾。
1.3 Java代碼實現(xiàn)
class Solution {public int minSubArrayLen(int target, int[] nums) {int ret = Integer.MAX_VALUE;for(int left = 0,right = 0, sum = 0; right < nums.length; right++) {sum += nums[right];while(sum >= target) {ret = Math.min(ret,right - left + 1);sum -= nums[left++];}}return ret == Integer.MAX_VALUE ? 0 : ret;}
}
2.無重復字符的最長子串
https://leetcode.cn/problems/longest-substring-without-repeating-characters/
2.1 題目要求
給定一個字符串 s ,請你找出其中不含有重復字符的 最長子串 的長度。
示例 1:
輸入: s = "abcabcbb"
輸出: 3
解釋: 因為無重復字符的最長子串是 "abc",所以其長度為 3。
示例 2:
輸入: s = "bbbbb"
輸出: 1
解釋: 因為無重復字符的最長子串是 "b",所以其長度為 1。
示例 3:
輸入: s = "pwwkew"
輸出: 3
解釋: 因為無重復字符的最長子串是 "wke",所以其長度為 3。請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
提示:
0 <= s.length <= 5 * 104
s 由英文字母、數(shù)字、符號和空格組成
class Solution {public int lengthOfLongestSubstring(String s) {}
}
2.2 做題思路
先來看看暴力解法如何解決
通過暴力解法,我們也可以發(fā)現(xiàn),每次循環(huán)找到的無重復字符的最長子串它的 left 的 right 都是向右移動的,所以這個題目同樣使用滑動窗口來解決。
因為這里求的是長度最長的無重復字符的子串,所以需要在進窗口的時候進行判斷是否需要更新最大長度,而判斷是否有重復的字符,我們可以借助哈希表來進行判斷。
2.3 Java代碼實現(xiàn)
class Solution {public int lengthOfLongestSubstring(String ss) {char[] s = ss.toCharArray();int[] hash = new int[128];int ret = 0;for(int left = 0, right = 0; right < s.length; right++) {char in = s[right];hash[in]++;if(hash[in] == 1) {ret = Math.max(ret,right - left + 1);}while(hash[in] > 1) {char out = s[left++];hash[out]--;}}return ret;}
}
3.最大連續(xù)1的個數(shù) III
https://leetcode.cn/problems/max-consecutive-ones-iii/
3.1 題目要求
給定一個二進制數(shù)組 nums 和一個整數(shù) k,如果可以翻轉最多 k 個 0 ,則返回 數(shù)組中連續(xù) 1 的最大個數(shù) 。
示例 1:
輸入:nums = [1,1,1,0,0,0,1,1,1,1,0], K = 2
輸出:6
解釋:[1,1,1,0,0,1,1,1,1,1,1]
粗體數(shù)字從 0 翻轉到 1,最長的子數(shù)組長度為 6。
示例 2:
輸入:nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
輸出:10
解釋:[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
粗體數(shù)字從 0 翻轉到 1,最長的子數(shù)組長度為 10。
提示:
1 <= nums.length <= 105
nums[i] 不是 0 就是 1
0 <= k <= nums.length
class Solution {public int longestOnes(int[] nums, int k) {}
}
3.2 做題思路
很多人看到這個翻轉0不知道啥意思,說通俗點就是0可以變成1,同樣,先來看看暴力解法如何解決。
left 指針和 right 指針都是向右方向移動的,所以這道題目同樣使用滑動窗口來解決。我們的判斷條件是以窗口內(nèi)0的數(shù)量為判斷條件,并且求的是最大長度,所以是在進窗口的時候進行判斷。
3.3 Java代碼實現(xiàn)
class Solution {public int longestOnes(int[] nums, int k) {int ret = 0;for(int left = 0, right = 0,count = 0; right < nums.length; right++) {if(nums[right] == 0) count++;if(count <= k) {ret = Math.max(ret,right - left + 1);}while(count > k) {if(nums[left++] == 0) count--;}}return ret;}
}
4.將x減到0的最小操作數(shù)
https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/
4.1 題目要求
給你一個整數(shù)數(shù)組 nums 和一個整數(shù) x 。每一次操作時,你應當移除數(shù)組 nums 最左邊或最右邊的元素,然后從 x 中減去該元素的值。請注意,需要 修改 數(shù)組以供接下來的操作使用。
如果可以將 x 恰好 減到 0 ,返回 最小操作數(shù) ;否則,返回 -1 。
示例 1:
輸入:nums = [1,1,4,2,3], x = 5
輸出:2
解釋:最佳解決方案是移除后兩個元素,將 x 減到 0 。
示例 2:
輸入:nums = [5,6,7,8,9], x = 4
輸出:-1
示例 3:
輸入:nums = [3,2,20,1,1,3], x = 10
輸出:5
解釋:最佳解決方案是移除后三個元素和前兩個元素(總共 5 次操作),將 x 減到 0 。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 104
1 <= x <= 109
class Solution {public int minOperations(int[] nums, int x) {}
}
4.2 做題思路
這道題目的意思就是:給定一個數(shù)字x,每次從數(shù)組的最左邊或者最右邊選擇一個數(shù)減去,然后使x減到0的最少的操作數(shù)。這道題目如果從正面去做的話,會先的非常麻煩,不妨我們換一條思路,他求的是數(shù)組兩邊減去的最少的數(shù)字,不妨我們就求數(shù)組中間最長的子數(shù)組,使它們的和為數(shù)組所有元素的總和減去 target ,這樣就能是數(shù)組的兩側的和為 target 并且長度最短。所以這個題目就跟前面的求數(shù)組長度最長的子數(shù)組是差不多的,就只是判斷的地方不同,這里需要在出窗口之后判斷是否需要更新ret的值,這里我就不給大家過多介紹了,關鍵就是能夠知道這個思路。
4.3 Java代碼實現(xiàn)
class Solution {public int minOperations(int[] nums, int x) {int sum = 0;for(int n : nums) sum += n; //求數(shù)組所有元素的總和int target = sum - x;if(target < 0) return -1;int ret = -1;for(int left = 0, right = 0,sum1 = 0; right < nums.length; right++) {sum1 += nums[right];while(sum1 > target) {sum1 -= nums[left++];}if(sum1 == target) {ret = Math.max(ret,right - left + 1);}}return ret == -1 ? -1 : nums.length - ret;}
}
5.水果成籃
https://leetcode.cn/problems/fruit-into-baskets/
5.1 題目要求
你正在探訪一家農(nóng)場,農(nóng)場從左到右種植了一排果樹。這些樹用一個整數(shù)數(shù)組 fruits 表示,其中 fruits[i] 是第 i 棵樹上的水果 種類 。
你想要盡可能多地收集水果。然而,農(nóng)場的主人設定了一些嚴格的規(guī)矩,你必須按照要求采摘水果:
- 你只有 兩個 籃子,并且每個籃子只能裝 單一類型 的水果。每個籃子能夠裝的水果總量沒有限制。
- 你可以選擇任意一棵樹開始采摘,你必須從 每棵 樹(包括開始采摘的樹)上 恰好摘一個水果 。采摘的水果應當* 符合籃子中的水果類型。每采摘一次,你將會向右移動到下一棵樹,并繼續(xù)采摘。
- 一旦你走到某棵樹前,但水果不符合籃子的水果類型,那么就必須停止采摘。
給你一個整數(shù)數(shù)組 fruits ,返回你可以收集的水果的 最大 數(shù)目。
示例 1:
輸入:fruits = [1,2,1]
輸出:3
解釋:可以采摘全部 3 棵樹。
示例 2:
輸入:fruits = [0,1,2,2]
輸出:3
解釋:可以采摘 [1,2,2] 這三棵樹。
如果從第一棵樹開始采摘,則只能采摘 [0,1] 這兩棵樹。
示例 3:
輸入:fruits = [1,2,3,2,2]
輸出:4
解釋:可以采摘 [2,3,2,2] 這四棵樹。
如果從第一棵樹開始采摘,則只能采摘 [1,2] 這兩棵樹。
示例 4:
輸入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
輸出:5
解釋:可以采摘 [1,2,1,1,2] 這五棵樹。
提示:
1 <= fruits.length <= 105
0 <= fruits[i] < fruits.length
class Solution {public int totalFruit(int[] fruits) {}
}
5.2 做題思路
根據(jù)題目我們可以知道,只有兩個籃子,只能裝兩種水果,并且每個籃子可以裝的水果數(shù)是無限的,這道題跟子數(shù)組的問題是類似的,只是判斷條件變成了水果的種類,進窗口的時候,添加水果的種類很簡單,當這個種類的水果數(shù)量在之前為0時,就說明是一個新的種類,但是當我們出窗口的時候,如果某一種類的水果數(shù)量減為0的時候,就需要減去一種種類,那么我們?nèi)绾谓y(tǒng)計某一水果的數(shù)量呢?哈希表,使用哈希表可以很高效的對某一種類的數(shù)量進行統(tǒng)計。
5.3 Java代碼實現(xiàn)
class Solution {public int totalFruit(int[] fruits) {int ret = 1;int[] hash = new int[fruits.length];for(int left = 0, right = 0,kinds = 0; right < fruits.length; right++) {int in = fruits[right];if(hash[in]++ == 0) kinds++;if(kinds <= 2) { //當水果的種類小于等于2的時候就需要做出判斷ret = Math.max(ret,right - left + 1);}while(kinds > 2) {int out = fruits[left++];if(--hash[out] == 0) kinds--;}}return ret;}
}
6.找到字符串中所有字母異位詞
https://leetcode.cn/problems/find-all-anagrams-in-a-string/
6.1 題目要求
給定兩個字符串 s 和 p,找到 s 中所有 p 的 異位詞 的子串,返回這些子串的起始索引。不考慮答案輸出的順序。
異位詞 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 1:
輸入: s = "cbaebabacd", p = "abc"
輸出: [0,6]
解釋:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的異位詞。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的異位詞。
示例 2:
輸入: s = "abab", p = "ab"
輸出: [0,1,2]
解釋:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的異位詞。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的異位詞。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的異位詞。
提示:
1 <= s.length, p.length <= 3 * 104
s 和 p 僅包含小寫字母
class Solution {public List<Integer> findAnagrams(String s, String p) {}
}
6.2 做題思路
這道題其實就相當于使用一個大小為 p 字符串長度的框從 s 字符串頭部開始框 p 字符串長度的字符串,然后判斷框起來的字符串是否是 p 字符串的異位詞。
窗口中的大小是確定的,最終的窗口的大小是p字符串的長度,也就是說我們的判斷條件就是窗口內(nèi)的字符串是否是p字符串的異位詞,這也是解決這道題的關鍵。那么我們應該如何解決呢?同樣是使用兩個哈希表,第一個哈希表統(tǒng)計p字符串每個單詞出現(xiàn)的次數(shù),當進窗口的時候,第二個哈希表中該字符出現(xiàn)的次數(shù)就加一,并且如果將這個字符添加進哈希表之后,該哈希表中對應字符出現(xiàn)的次數(shù)小于等于第一個哈希表對應字符出現(xiàn)的次數(shù),就說明進窗口的這個字符為有效字符,我們使用 count 來記錄有效字符的個數(shù),count++,當 count 等于 p 字符串的長度時,就需要更新結果:將 left 的坐標添加進列表中。
6.3 Java代碼實現(xiàn)
class Solution {public List<Integer> findAnagrams(String ss, String pp) {List<Integer> list = new ArrayList<>();char[] s = ss.toCharArray();char[] p = pp.toCharArray();int[] hash1 = new int[26];int[] hash2 = new int[26];for(char ch : p) hash1[ch - 'a']++;int len = p.length;for(int left = 0, right = 0,count = 0; right < s.length; right++) {char in = s[right];if(++hash2[in - 'a'] <= hash1[in - 'a']) count++;if(right - left + 1 > len) {char out = s[left++];if(hash2[out - 'a']-- <= hash1[out - 'a']) count--;}if(count == len) {list.add(left);}}return list;}
}
7.串聯(lián)所有單詞的子串
https://leetcode.cn/problems/substring-with-concatenation-of-all-words/
7.1 題目要求
給定一個字符串 s 和一個字符串數(shù)組 words。 words 中所有字符串 長度相同。
s 中的 串聯(lián)子串 是指一個包含 words 中所有字符串以任意順序排列連接起來的子串。
- 例如,如果 words = [“ab”,“cd”,“ef”], 那么 “abcdef”, “abefcd”,“cdabef”, “cdefab”,“efabcd”, 和 “efcdab” 都是串聯(lián)子串。 “acdbef” 不是串聯(lián)子串,因為他不是任何 words 排列的連接。
返回所有串聯(lián)子串在 s 中的開始索引。你可以以 任意順序 返回答案。
示例 1:
輸入:s = "barfoothefoobarman", words = ["foo","bar"]
輸出:[0,9]
解釋:因為 words.length == 2 同時 words[i].length == 3,連接的子字符串的長度必須為 6。
子串 "barfoo" 開始位置是 0。它是 words 中以 ["bar","foo"] 順序排列的連接。
子串 "foobar" 開始位置是 9。它是 words 中以 ["foo","bar"] 順序排列的連接。
輸出順序無關緊要。返回 [9,0] 也是可以的。
示例 2:
輸入:s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"]
輸出:[]
解釋:因為 words.length == 4 并且 words[i].length == 4,所以串聯(lián)子串的長度必須為 16。
s 中沒有子串長度為 16 并且等于 words 的任何順序排列的連接。
所以我們返回一個空數(shù)組。
示例 3:
輸入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]
輸出:[6,9,12]
解釋:因為 words.length == 3 并且 words[i].length == 3,所以串聯(lián)子串的長度必須為 9。
子串 "foobarthe" 開始位置是 6。它是 words 中以 ["foo","bar","the"] 順序排列的連接。
子串 "barthefoo" 開始位置是 9。它是 words 中以 ["bar","the","foo"] 順序排列的連接。
子串 "thefoobar" 開始位置是 12。它是 words 中以 ["the","foo","bar"] 順序排列的連接。
提示:
1 <= s.length <= 104
1 <= words.length <= 5000
1 <= words[i].length <= 30
words[i] 和 s 由小寫英文字母組成
class Solution {public List<Integer> findSubstring(String s, String[] words) {}
}
7.2 做題思路
這道題目跟上面的一個題目是類似的,只是這里將字母換成了單詞,所以我們可以仿照上面一個題的思路,將words數(shù)組中的每個字符串當作一個字母,s 字符串每與words數(shù)組中每個單詞相同長度的字符串作為一個字母。
因為不僅可以從 b 開始,將字符數(shù)組分為多個字符串,還可以從a和r開始,所以這里我們需要進行 words 數(shù)組中每個單詞長度的循環(huán)次數(shù)的操作。
這里的哈希表用數(shù)組就不容易模擬了,所以這里就需要用到 HashMap
7.3 Java代碼實現(xiàn)
class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> list = new ArrayList<>();Map<String,Integer> map1 = new HashMap<>();for(String tmp : words) {map1.put(tmp,map1.getOrDefault(tmp,0) + 1);}int len = words.length; //求words數(shù)組的大小int m = words[0].length(); //求words數(shù)組中每個單詞的長度for(int i = 0; i < m; i++) {Map<String,Integer> map2 = new HashMap<>();for(int left = i, right = i, count = 0; right <= s.length()-m; right += m) {String in = s.substring(right,right + m);map2.put(in,map2.getOrDefault(in,0) + 1);if(map2.get(in) <= map1.getOrDefault(in,0)) count++;if(right - left + 1 > len * m) {String out = s.substring(left,left + m);if(map2.get(out) <= map1.getOrDefault(out,0)) count--;map2.put(out,map2.get(out) - 1);left += m;}if(count == len) list.add(left);}}return list;}
}
8.最小覆蓋字串
https://leetcode.cn/problems/minimum-window-substring/
8.1 題目要求
給你一個字符串 s 、一個字符串 t 。返回 s 中涵蓋 t 所有字符的最小子串。如果 s 中不存在涵蓋 t 所有字符的子串,則返回空字符串 “” 。
注意:
對于 t 中重復字符,我們尋找的子字符串中該字符數(shù)量必須不少于 t 中該字符數(shù)量。
如果 s 中存在這樣的子串,我們保證它是唯一的答案。
示例 1:
輸入:s = "ADOBECODEBANC", t = "ABC"
輸出:"BANC"
解釋:最小覆蓋子串 "BANC" 包含來自字符串 t 的 'A'、'B' 和 'C'。
示例 2:
輸入:s = "a", t = "a"
輸出:"a"
解釋:整個字符串 s 是最小覆蓋子串。
示例 3:
輸入: s = "a", t = "aa"
輸出: ""
解釋: t 中兩個字符 'a' 均應包含在 s 的子串中,
因此沒有符合條件的子字符串,返回空字符串。
提示:
m == s.length
n == t.length
1 <= m, n <= 105
s 和 t 由英文字母組成
class Solution {public String minWindow(String s, String t) {}
}
8.2 做題思路
因為這道題目中說了,可以出現(xiàn)重復的字符,所以這道題的判斷條件就是窗口中是否含有 t 字符串中的所有字符,并且窗口中的每個字符出現(xiàn)的次數(shù)必須大于 t 字符串中每個字符出現(xiàn)的次數(shù)。那么這道題的步驟主要分為兩步:
- 在s字符串中,找到含有 t 字符串中含有的所有字符的窗口
- 在這個窗口中找長度最小的子串
8.3 Java代碼實現(xiàn)
class Solution {public String minWindow(String ss, String tt) {char[] s = ss.toCharArray();char[] t = tt.toCharArray();int[] hash1 = new int[128];int[] hash2 = new int[128];int kinds = 0;for(char ch : t) {if(hash1[ch]++ == 0) kinds++;}int begin = -1;int minLen = Integer.MAX_VALUE;for(int left = 0, right = 0,count = 0; right < s.length; right++) {char in = s[right];if(++hash2[in] == hash1[in]) count++;while(count == kinds) {if(right - left + 1 < minLen) {begin = left;minLen = right - left + 1;}char out = s[left++];if(hash2[out]-- == hash1[out]) count--;}}if(begin == -1) return new String();else return ss.substring(begin,begin + minLen);}
}
總結
當涉及到解決子串或子數(shù)組的問題時,滑動窗口算法是一種非常有效的技術。它通過維護一個窗口,該窗口在字符串或數(shù)組上滑動,以解決特定問題。
滑動窗口算法的主要思想是使用兩個指針,一個指向窗口的起始位置,另一個指向窗口的結束位置。通過調(diào)整這兩個指針,可以擴展或收縮窗口,以找到所需的解。算法的關鍵是確定窗口的移動規(guī)則以及如何在移動過程中更新解。
下面是滑動窗口算法的一般步驟:
- 初始化窗口的起始指針和結束指針,使其指向合理的位置。
- 進入一個循環(huán),不斷嘗試擴展窗口,直到窗口無法再擴展為止。
- 在每次窗口移動時,更新解(如果有必要)。
- 如果窗口仍然滿足問題的要求,嘗試收縮窗口,以尋找更優(yōu)的解。
- 重復步驟3和4,直到窗口完全收縮并處理完所有元素。
滑動窗口算法的優(yōu)點是其時間復雜度通常是線性的,因為它避免了對每個子串或子數(shù)組的重復計算,節(jié)約了計算資源。它也通??梢栽贠(1)的空間復雜度下完成。
滑動窗口算法常用于解決一些經(jīng)典問題,例如字符串匹配、子數(shù)組和子串求和、最長/最短子數(shù)組等。通過適當定義窗口的移動規(guī)則和解的更新方式,可以針對不同的具體問題進行定制化的實現(xiàn)。
總結而言,滑動窗口算法是一種高效的解決子串或子數(shù)組問題的方法。它的核心思想是通過維護一個窗口,在問題的限定條件下移動窗口的起始和結束指針,同時利用解的特性來優(yōu)化計算過程。使用滑動窗口算法可以提高問題的解決效率,并減少不必要的計算。