深度解析算法之滑動窗口

12滑動窗口—將 x 減到 0 的最小操作數

題目傳送門

題目描述:

給你一個整數數組?nums?和一個整數?x?。每一次操作時,你應當移除數組?nums?最左邊或最右邊的元素,然后從?x?中減去該元素的值。請注意,需要?修改?數組以供接下來的操作使用。
如果可以將?x?恰好?減到?0?,返回?最小操作數?;否則,返回?-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里面的數據,我們可以發現最優的操作次數是2次image.png

對于示例2來說的話,我們不論是從左邊還是右邊進行刪除操作,我們的x永遠不可能到0的,所以我們返回-1

現在我們將問題進行轉換:原來要求的是我們從最左邊或者是最右邊進行x刪除元素,直到x變成0。那么我們可以將這個進行區域劃分,如下圖,左邊的區域是a,右邊的區域是b,a區域和b區域里面的數值加起來等于x,那么我們中間剩下的就是我們整個數組的值減去x,題目讓我們求出最小的操作次數,那么就是說我們a+b最短的情況,換種思路,就是中間區域最長的情況,即sum-x,我們只要求出整個數組中和為sum-x的區域的最長值就行了
image.png
找出最長的子數組的長度,子數組的所有元素的和正好等于sum-x

做這種題我們可以想對立面

我們可以先想想 暴力解法:我們設置兩個指針,左和右,我們讓兩個指針一開始指向起點,然后讓右指針進行移動操作,直到我們的兩個指針的區域間的值大于等于sum-x,我們就更新下我們的操作次數,然后移動我們的左指針繼續進行更新的操作image.png
當我們的左指針往右邊移動了,那么我們的右指針就沒有必要往左邊進行移動了,因為我們左指針向右移動過后,我們的兩個指針區間中的元素大小更小了,我們右指針只能往右移動

那么我們現在在這個暴力解法的基礎上進行優化
image.png

class Solution {public:int minOperations(vector<int>& nums, int x){int sum =0;for(int a:nums){sum+=a;}int target =sum-x;//細節問題,target的值不能小于0if(target<0) return -1;int ret=-1;for(int left=0,right=0,tmp=0;right<nums.size();right++){//tmp來計算我們左右指針中間的值的大小的tmp+=nums[right];//進窗口的操作while(tmp>target)//進行判斷,如果區間中的值大于了target我們就停下來{tmp-=nums[left];left++;//出窗口}if(tmp==target)//更新結果{//更新我們兩個指針中間的長度ret=max(ret,right-left+1);}}if(ret==-1) return ret;//沒有找到else return nums.size()-ret;//找到的話我們直接返回我們的這個總長度減去我們中間的值}};

13滑動窗口—水果成籃

題目傳送門
你正在探訪一家農場,農場從左到右種植了一排果樹。這些樹用一個整數數組?fruits?表示,其中?fruits[i]?是第?i?棵樹上的水果?種類?。

你想要盡可能多地收集水果。然而,農場的主人設定了一些嚴格的規矩,你必須按照要求采摘水果:

  • 你只有?兩個?籃子,并且每個籃子只能裝?單一類型?的水果。每個籃子能夠裝的水果總量沒有限制。
  • 你可以選擇任意一棵樹開始采摘,你必須從?每棵?樹(包括開始采摘的樹)上?恰好摘一個水果?。采摘的水果應當符合籃子中的水果類型。每采摘一次,你將會向右移動到下一棵樹,并繼續采摘。
  • 一旦你走到某棵樹前,但水果不符合籃子的水果類型,那么就必須停止采摘。

給你一個整數數組?fruits?,返回你可以收集的水果的?最大?數目。

示例 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] 這五棵樹。

我們現在有兩個籃子進行摘水果,然后每個籃子只能裝一個水果,不能裝多種水果,我們現在按實例2來說,示例二我們先采摘0號水果,然后再采摘1號水果,然后我們就不能采摘了,因為再后面的2號水果和1號水果種類不同,所以我們是只能采摘2棵樹,但是我們如果從1號開始采摘的話,我們然后可以摘2號水果,我們再還能接著采摘2號水果,所以我們這種方案是可以采摘3棵樹的

就是我們的兩個籃子只能裝兩種類型的水果,就是一個區間只能存在兩種數字,不能存在第三種數字

轉化: 找出一個最長的子數組,子數組里面不超過兩種類型的水果

暴力解法:直接將所有的子數組都給找出來,找出其中最長的一個
我們可以借助一個哈希表來記錄我們當前出現水果種類的次數

我們現在定義兩個指針,左和右,兩個指針都從最開始的位置行動,右指針保持運行,直到我們水果的種類大于2了,我們就停下來,那么此時左和右中間的區域就是我們要求的
然后我們的左指針往右運行,那么我們就得想想我們的右指針回不回來呢?是不是和左指針重新開始還是說直接從上次的位置開始
我們的左指針往右運行,那么我們水果種類只能出現兩種:不變或者是變小,絕不可能變大,因為我們左往右走了一步,水果少了一個

如果這個在左指針運行后,我們水果的種類不變的話,我們右指針就沒必要品回來了

如果水果種類減少的話,那么我們區間里面還是只存在一種類型的結果,我們的右指針也是沒有必要回去的,右指針直接右移image.png
那么我們就可以使用滑動窗口進行解答了

進窗口的操作就是將我們右指針指向的元素丟到哈希表中
如果這個哈希表的長度大于2的話,我們就進行出窗口的操作
在哈希表中,我們不僅僅存入這個水果的種類,還要存入水果的數量

在出窗口的時候我們還要對我們哈希表中的元素進行判斷,如果某種種類的水果數量變成了0的話,那么我們要將這個水果從哈希表中刪除的

下面是我們的代碼

class Solution {public:int totalFruit(vector<int>& f){unordered_map<int ,int>hash;//統計窗口內出現多少種水果int ret=0;for(int left=0,right=0;right<f.size();right++){hash[f[right]]++;//進窗口while(hash.size()>2)//進行判斷,查看我們哈希表中的水果種類是否大于2{//出窗口操作hash[f[left]]--;//因為我們當前left要往右邊走,那么我們就得判斷下我們這個減少數量的這個水果的個數是否變成了0if(hash[f[left]]==0)//如果這個水果數量變成了0的話,那么我們就得將這個水果從哈希表中刪除了{hash.erase(f[left]);//將這個種類變為0的水果從哈希表中刪除}left++;//左指針往右邊走}ret=max(ret,right-left+1);//更新結果,結果就是我們左右指針中間的區間的長度}return ret;}};

image.png
但是我們發現我們的這個時間復雜度不行,因為我們哈希表中插入刪除元素
所以我們這里是可以進行優化的操作的,對當前的哈希表進行優化操作

我們可以直接利用一個數組來創建哈希表,并且增加一個變量kinds來表示我們水果的種類
下面我們就是直接利用數組進行操作

class Solution {public:int totalFruit(vector<int>& f){int hash[100001]={0};//統計窗口內出現多少種水果int ret=0;for(int left=0,right=0,kinds=0;right<f.size();right++){//如果當前right指針指向的水果的個數為0的話,我們就種類++if(hash[f[right]]==0) kinds++;//維護水果的種類hash[f[right]]++;//進窗口while(kinds>2)//進行判斷,查看我們哈希表中的水果種類是否大于2{//出窗口操作hash[f[left]]--;//因為我們當前left要往右邊走,那么我們就得判斷下我們這個減少數量的這個水果的個數是否變成了0if(hash[f[left]]==0)//如果這個水果數量變成了0的話,我們直接讓種類減一{kinds--;}left++;//左指針往右邊走}ret=max(ret,right-left+1);//更新結果,結果就是我們左右指針中間的區間的長度}return ret;}};

14滑動窗口_找到字符串中所有字母異位詞

題目鏈接

給定兩個字符串?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” 的異位詞

我們需要快速判斷兩個字符串是異位詞,我們可以通過比較兩個字符串來比較判斷是否是異位詞
image.png
操作方式就是利用哈希表來進行計數
下方就是暴力解法:不斷的比較
image.png

一次移動len個子串然后和另一個子串進行比較,那么我們這里是可以用滑動窗口進行解答的
image.png

利用count來統計窗口中有效字符的個數
進窗口后我們考慮下我們進窗口的這個數據是否是有效的數據,這個字母的出現個數是否個另一個字符串里面對應字母的出現次數相等

出窗口之前我們判斷下我們出去這個字符是否是有效字符,是有效字符的話那么我們就進行count–操作

然后我們更新結果

class Solution {public:vector<int> findAnagrams(string s, string p){vector<int >ret;int hash1[26]={0};//統計字符串p中每個字符出現的個數for(auto ch:p){hash1[ch-'a']++;//對應字符的下標,統計對應字母出現的次數}int hash2[26]={0};//統計窗口里面的每一個字符出現的個數int m=p.size();for(int left=0,right=0,count=0;right<s.size();right++){char in =s[right];//進窗口hash2[in-'a']++;//統計對應字符出現的個數if(hash2[in-'a']<=hash1[in-'a']) count++;//如果s中的這個字符的出現次數小于p中字符出現的個數的話,那么有效字符要++的if(right-left+1>m)//判斷,這個就是窗口大了,我們得進行出窗口的操作{//出窗口&&維護countchar out=s[left++];//將這個元素丟出去,將這個元素丟出去,我們的left往右走if(hash2[out-'a']<=hash1[out-'a']) count--;//如果滿足條件的話,那么就說明當前滑出去的是一個有效字符hash2[out-'a']--;}//更新if(count==m) ret.push_back(left);//直接將起始位置的下標進行輸出}return ret;}};

說白了就是一直維持這個count的大小,然后知道count的大小等于這個p字符串的長度了,我們就將起始的左指針進行返回的操作

15滑動窗口—串聯所有單詞的子串

題目鏈接

給定一個字符串?s?和一個字符串數組?words?words?中所有字符串?長度相同

s?中的?串聯子串?是指一個包含??words?中所有字符串以任意順序排列連接起來的子串。

  • 例如,如果?words = ["ab","cd","ef"], 那么?"abcdef",?"abefcd""cdabef",?"cdefab""efabcd", 和?"efcdab"?都是串聯子串。?"acdbef"?不是串聯子串,因為他不是任何?words?排列的連接。

返回所有串聯子串在?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,所以串聯子串的長度必須為 16。
s 中沒有子串長度為 16 并且等于 words 的任何順序排列的連接。
所以我們返回一個空數組。

示例 3:

輸入: s = “barfoofoobarthefoobarman”, words = [“bar”,“foo”,“the”]
輸出:[6,9,12]
解釋: 因為 words.length == 3 并且 words[i].length == 3,所以串聯子串的長度必須為 9。
子串 “foobarthe” 開始位置是 6。它是 words 中以 [“foo”,“bar”,“the”] 順序排列的連接。
子串 “barthefoo” 開始位置是 9。它是 words 中以 [“bar”,“the”,“foo”] 順序排列的連接。
子串 “thefoobar” 開始位置是 12。它是 words 中以 [“the”,“foo”,“bar”] 順序排列的連接。

我們可以將題目進行轉換,在左邊的字符串中找到我們右邊的a b的異位詞就行了,那么這個題就很像之前的那個找到字符串中所有字母異位詞這個題了
image.png
找到一個字符串就返回起始位置

那么這個題我們就會使用到滑動窗口和哈希表了

相較于找到字符串中所有字母異位詞這個題的話,我們有三點不同

  • 哈希表
    之前的那題我們里面的哈希表存儲的是一個個的字符,這里的話我們是一個又一個的字符串

  • left和right指針的移動
    因為我們字符串數組里面的字符串的長度都是相等的,那么我們在移動的時候為了讓新的字符串進入到窗口的話,那么我們每次移動的話是需要前進len個距離,len就是我們單個字符串的長度
    移動的步長是每個單詞的長度

  • 滑動窗口的執行次數
    我們滑動窗口執行的次數是len次
    因為我們的指針不僅僅是從第一個位置開始的,也可能從第二個位置,甚至第len個位置,如果從len+1的位置開始的話,那么就是重復了,和從第一個位置開始的情況重疊了,所以我們進行滑動窗口的次數是len次
    image.png

class Solution {public:vector<int> findSubstring(string s, vector<string>& words){vector<int> ret;//創建一個哈希表并且將單詞在word中出現的次數進行記錄unordered_map<string, int> hash1;;//保存words里面所有的單詞的頻次for(auto& s:words) hash1[s]++;//記錄words里面所有的單詞出現的頻次//計算單詞的長度int len=words[0].size(),m=words.size();//多少個單詞//我們這里的滑動窗口是需要執行len次的for(int i=0;i<len;i++)//執行len次滑動窗口{unordered_map<string,int>hash2;//維護滑動窗口內單詞的頻次//因為我們right在移動到對應的位置后,我們需要將right+len個字符放到滑動窗口里面去for(int left=i,right=i,count=0;right+len<=s.size();right+=len)//count就是有效字符串的個數了{//進窗口+維護countstring in =s.substr(right,len);//直接獲取right后面len個字符,那么in就是一個字符串了hash2[in]++;//我們將in這個字符出現的頻次進行更新if(hash2[in]<=hash1[in]) count++;//如果我們hash2這個哈希中當前字符串出現的頻次小于hash1的話,說明是有效單詞,如果我們哈希2里面這個字符串出現次數大于哈希1的話,那么這個肯定是一個無效的單詞,因為hash1中都沒有進行記錄//判斷if(right-left+1>len*m)//如果我們當前左右指針的范圍大于我們要找的子串的長度的話,那么我們就進行出窗口操作{//出窗口,維護countstring out=s.substr(left,len);//我們將left后面三個單詞的范圍的這個字符串拿出來if(hash2[out]<=hash1[out]) count--;//有效單詞減一hash2[out]--;//出完窗口之后,我們的left需要向后移動left+=len;}//更新結果if(count==m) ret.push_back(left);//將我們}}//當整個循環結束之后,我們ret中存儲的就是結果了return ret;}};

我們先創建一個哈希1,用來存儲我們words中的單詞出現的次數,利用范圍for獲得每個單詞出現的頻次

然后我們再計算len就是每個單詞的長度,因為這個題中每個單詞的長度都是一樣的
然后我們再來一個for循環,次數就是len次,因為我們的左指針有效循環的次數就是len次,如果是len+1次的話,那么結果是和第一次的結果是相同的

在這個for循環中我們再來一個for循環進行進窗口的操作,在進窗口之前我們需要創建一個哈希2來記錄我們滑動窗口內單詞的頻次

這個內循環的我們需要維護好count,就是窗口內有效單詞的數量,如果沒有在哈希1中出現過的,統統都是無效單詞,出現過的才算是有效單詞

然后我們進行進窗口的操作,利用substr獲取我們right后面len個范圍的單詞,將這個字符串放到in中,然后給hash2記錄這個單詞出現的次數,我們在進窗口后我們維護好我們的count,如果當前的單詞在hash2中出現的次數小于hash1中出現的次數的話,那么就證明這個單詞是有效的,為什么呢?因為如果hash2中這個單詞出現的次數大于hash1中的話,那么這個單詞就是無效的,在hash1中不存在的,所以hash2中出現次數小于等于hash1中單詞的次數的話,那么在這個單詞就是有效的單詞,那么我們count++

然后我們進行判斷,如果我們當前的right和left的范圍大于我們words中字符串組合成的字符串的長度的話,那么我們就進行出窗口的操作,我們就得將我們的left往右邊進行移動了,還是利用substr獲取我們left后面len個字符的字符串,將這個字符串存在out中,然后將hash2中的out這個字符串給減一,在減一之前我們還需要維護下我們的count,對我們這個單詞進行判斷,是否是有效的單詞

出完窗口后,我們的left需要往右邊進行移動,移動的距離是len
然后我們進行結果的更新,如果我們count=m的話,那么我們將此時的left,就是這個對應字符串的開始位置存儲子啊我們的vector容器中去

最后直接返回了

但是吧,我們當前的這個效率比較慢,因為我們在判斷當前的字符串是否是有效的字符串的時候,如果我們這個字符串in在hash1中不存在 的話,那么我們就得進行創建hash1[in]了,所以這里是存在效率變低的,所以我們可以在判斷條件中加上hash1.count(in)來判斷我們的這個單詞的數量,如果是0的話,我們 直接退出了這個條件判斷了

class Solution {public:vector<int> findSubstring(string s, vector<string>& words){vector<int> ret;//創建一個哈希表并且將單詞在word中出現的次數進行記錄unordered_map<string, int> hash1;;//保存words里面所有的單詞的頻次for(auto& s:words) hash1[s]++;//記錄words里面所有的單詞出現的頻次//計算單詞的長度int len=words[0].size(),m=words.size();//多少個單詞//我們這里的滑動窗口是需要執行len次的for(int i=0;i<len;i++)//執行len次滑動窗口{unordered_map<string,int>hash2;//維護滑動窗口內單詞的頻次//因為我們right在移動到對應的位置后,我們需要將right+len個字符放到滑動窗口里面去for(int left=i,right=i,count=0;right+len<=s.size();right+=len)//count就是有效字符串的個數了{//進窗口+維護countstring in =s.substr(right,len);//直接獲取right后面len個字符,那么in就是一個字符串了hash2[in]++;//我們將in這個字符出現的頻次進行更新if(hash1.count(in)&&hash2[in]<=hash1[in]) count++;//如果我們hash2這個哈希中當前字符串出現的頻次小于hash1的話,說明是有效單詞,如果我們哈希2里面這個字符串出現次數大于哈希1的話,那么這個肯定是一個無效的單詞,因為hash1中都沒有進行記錄//判斷if(right-left+1>len*m)//如果我們當前左右指針的范圍大于我們要找的子串的長度的話,那么我們就進行出窗口操作{//出窗口,維護countstring out=s.substr(left,len);//我們將left后面三個單詞的范圍的這個字符串拿出來if(hash1.count(out)&&hash2[out]<=hash1[out]) count--;//有效單詞減一hash2[out]--;//出完窗口之后,我們的left需要向后移動left+=len;}//更新結果if(count==m) ret.push_back(left);//將我們}}//當整個循環結束之后,我們ret中存儲的就是結果了return ret;}};

16滑動窗口—最小覆蓋子串

題目鏈接
給你一個字符串?s?、一個字符串?t?。返回?s?中涵蓋?t?所有字符的最小子串。如果?s?中不存在涵蓋?t?所有字符的子串,則返回空字符串?""?。

注意:

  • 對于?t?中重復字符,我們尋找的子字符串中該字符數量必須不少于?t?中該字符數量。
  • 如果?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 的子串中,
因此沒有符合條件的子字符串,返回空字符串。

只要我們的s中可以將t全部涵蓋了的話,那么就是符合要求的
使用暴力解決,如果hash2中的ABC的次數大于hash1中的次數的話,那么hash2里面存的這一段字符串就是有效的字符串了

image.png
然后接下來從D這個位置接著枚舉,就這種暴力解決的方法

解法一:暴力枚舉+哈希表

那么我們是否可以在這個解法的基礎上進行優化呢
我們在找到符合要求的一組之后,我們的left往右走,那么此時我們的right是沒有必要回去的
image.png
如果我們原先left指向的元素他的出現次數太多了或者是一個無效的,那么我們的left往右邊移動一位,和此時right組成的區間依舊是有效的

但是如果我們原先left指向的元素是一個有效字符并且出現次數的小于我們hash1中的次數,那么我們此時的區間就是不符合要求的,我們的right依舊不用回來,繼續向后面走,直到找到了符合要求的那個元素為止

那么優化的方案就是滑動窗口+哈希表

當我們的窗口合法之后我們再進行出窗口的操作image.png
優化操作
我們使用count標記有效字符的種類 ,我們這里需要hash2中出現hash1中所有種類的字符,而不是個數,我們一定要按照有效字符種類來進行操作

我們進窗口的時候維護一下count,出窗口的時候維護一下count,判斷的時候判斷一下count

class Solution {public:string minWindow(string s, string t){int hash1[128]={0};//統計t字符串中每一個字符出現的頻次int kinds=0;//統計有效字符有多少種for(auto ch:t){//如何判斷我們當前的有效字符種類是否增加了呢?//如果在進窗口前這個字符數量為0 的話,并且是有效字符的話,那么我們的種類就多了一種了if(hash1[ch]==0) kinds++;//有效字符的種類加一hash1[ch]++;}//出了循環我們就統計到了我們字符的種類數量int hash2[128]={0};//統計窗口內每個字符的頻次int minlen=INT_MAX,begin=-1;for(int left=0,right=0,count=0;right<s.size();right++){char in=s[right];//獲取我們這個字符的信息hash2[in]++;//給這個字符的次數++//判斷我們加入的字符是否是有效字符//進窗口+維護count變量if(hash2[in]==hash1[in]) count++;//說明我們加入了一個有效的字符//判斷條件while(count==kinds){//更新結果if(right-left+1<minlen)//說明此時我們需要更新結果了{//計算最小的子串的長度minlen=right-left+1;//開始的指針指向我們的leftbegin=left;}//出窗口char out =s[left];//記錄當前出窗口的單詞left++;//左指針往右邊走//維護countif(hash2[out]==hash1[out])count--;//說明我們當前的字符是有效字符hash2[out]--;//將當前出窗口的字符進行--操作}}if(begin==-1) return "";//如果我們開始的指針沒有變的話,那么我們就直接返回空就行了else return s.substr(begin,minlen);//如果變了的話,我們begin后面minlen個范圍的字符串獲取然后返回就行了}};

我們先創建hash1來記錄我們t中字符出現的次數,創建變量kinds記錄種類,
然后我們遍歷t,獲取我們的種類的數量,并且記錄字符出現的頻次

然后我們創建hash2來記錄我們窗口中的每個字符出行的頻次
創建變量minlen記錄我們當前最小的子串長度,以及開始的指針begin

然后我們進入到滑動窗口的操作,我們先獲取我們right指針的位置上的元素,并且在hash2中記錄出現的次數
然后我們在進窗口后判斷下當前進的這個字符是否是有效的字符,并且進行維護我們的count(字符種類)
是否是有效的字符,我們依靠這段代碼hash2[in]==hash1[in],如果我們hash2中進的這個字符的次數等于我們hash1中字符的次數的話,那么我們就判定當前字符是有效的
如果有效的話,那么我們當前的count就++

進行判斷,如果我們的count的大小等于我們的kinds的話,就是說明我們當前的窗口就是一個有效的窗口了
那么我們就進行結果的更新操作
記錄我們當前區間的長度:right-left+1 并且記錄我們當前的begin

然后我們再進行出窗口的操作,我們記錄我們當前left位置的元素,然后從hash2中減少次數
并且我們在減少次數之前我們需要判斷下我們這個出窗口的元素是否是有效的字符,

最后出了循環,我們就返回對應的結果了

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/75411.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/75411.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/75411.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[MySQL初階]MySQL表的操作

MySQL表的操作 1. 創建表2. 查看表結構3. 修改表&#xff08;修改表的屬性而非表的數據&#xff09;4. 刪除表 1. 創建表 語法&#xff1a; CREATE TABLE table_name (field1 datatype,field2 datatype,field3 datatype ) character set 字符集 collate 校驗規則 engine 存儲…

sqlalchemy詳細介紹以及使用方法

SQLAlchemy是一個Python的ORM&#xff08;對象關系映射&#xff09;工具&#xff0c;它允許開發者使用Python代碼來操作數據庫而不必直接編寫SQL語句。SQLAlchemy提供了一種抽象層&#xff0c;使開發者可以通過簡單的Python對象來表示數據庫表和記錄&#xff0c;從而實現對數據…

圖解AUTOSAR_SWS_LINDriver

AUTOSAR LIN驅動詳解文檔 基于AUTOSAR標準的本地互聯網絡(LIN)驅動程序技術規范解析 目錄 1. 概述 1.1 AUTOSAR LIN驅動簡介1.2 LIN協議基礎2. LIN驅動架構 2.1 類圖結構2.2 狀態機設計3. LIN幀結構 3.1 基本幀組成3.2 PID結構4. LIN驅動配置 4.1 主要配置參數4.2 配置結構5. L…

《網絡管理》實踐環節03:snmp服務器上對網絡設備和服務器進行初步監控

蘭生幽谷&#xff0c;不為莫服而不芳&#xff1b; 君子行義&#xff0c;不為莫知而止休。 應用拓撲圖 3.0準備工作 所有Linux服務器上&#xff08;服務器和Agent端&#xff09;安裝下列工具 yum -y install net-snmp net-snmp-utils 保證所有的HCL網絡設備和服務器相互間能…

2025年內外網文件交換系統排名分析

在時代&#xff0c;企業的日常運營離不開內外網文件的交換。然而&#xff0c;傳統的文件傳輸方式難以滿足企業對多方面的要求。以下是一些備受關注的內外網文件交換系統及其排名分析。 第一名&#xff1a;陽途內外網文件交換系統 陽途內外網文件交換系統是一款專為解決內外網…

【Centos】centos7內核升級-親測有效

相關資源 通過網盤分享的文件&#xff1a;腳本升級 鏈接: https://pan.baidu.com/s/1yrCnflT-xWhAPVQRx8_YUg?pwd52xy 提取碼: 52xy –來自百度網盤超級會員v5的分享 使用教程 將腳本文件上傳到服務器的一個目錄 執行更新命令 yum install -y linux-firmware執行腳本即可 …

Qt進階開發:QDirModel的使用

文章目錄 一、QDirModel的基本介紹二、QDirModel的基本使用2.1 在 QTreeView 中顯示文件系統2.2 在 QListView 顯示當前目錄2.3 在 QTableView 中使用 三、QDirModel的常用API1. 構造 & 目錄操作1.1 創建 QDirModel1.2 設置根目錄 2. 過濾 & 排序2.1 過濾文件類型2.2 設…

牛客 除2問題

除2&#xff01; 貪心堆 讓偶數入堆 注意點&#xff1a; 1.判斷堆是否為空再進行操作 2. 為了防止超時&#xff0c;我們采取先求和的方式&#xff0c;后面調整之后再減掉&#xff0c;可以節省一次遍歷的時間。 3.注意數據范圍&#xff0c;要用long long #include<iost…

#MySQL 語句大全(完整實用教程)

&#x1f4cc; MySQL 語句大全&#xff08;完整實用教程&#xff09; &#x1f4cc; 1. 數據庫操作 ? 創建數據庫 CREATE DATABASE mydb; -- 創建名為 mydb 的數據庫? 使用數據庫 USE mydb; -- 選擇數據庫? 刪除數據庫 DROP DATABASE mydb; -- 刪除數據庫&#xff08…

萬字重談C++——類和對象篇

什么是類&#xff1f; 在編程中&#xff0c;類是用來創建對象的模板。可以把類看作一個藍圖&#xff0c;它定義了對象的屬性&#xff08;特征&#xff09;和方法&#xff08;行為&#xff09;。例如&#xff0c;如果我們有一個“學生”的類&#xff0c;它可能包含學生的名字、…

18認識Qt坐標系

平面直角坐標系(笛卡爾坐標系) 數學上的坐標系 右手坐標系 計算機中的坐標系 左手坐標系 坐標系的原點(0,0) 就是屏幕的左上角 /窗口的左上角 給 Qt 的某個控件,設置位置,就需要指定坐標.對于這個控件來說, 坐標系原點就是相對于父窗口/控件的. QPushButton 的父元素/父控件/父…

量子計算與人工智能的結合:未來科技的雙重革命

引言 在過去幾十年里&#xff0c;人工智能&#xff08;AI&#xff09;和計算能力的提升一直是推動科技進步的重要力量。然而&#xff0c;隨著深度學習和大規模數據處理的發展&#xff0c;傳統計算架構的算力瓶頸逐漸顯現&#xff0c;人工智能的訓練和推理效率受到了限制。在此背…

SEO長尾詞優化策略精要

內容概要 長尾關鍵詞優化是SEO策略中實現精準流量捕獲的核心環節。本文從定位方法、搜索意圖分析、詞庫構建三個維度切入&#xff0c;系統闡述如何通過數據化工具篩選高轉化潛力詞&#xff0c;并結合用戶行為路徑優化內容架構。具體而言&#xff0c;內容將覆蓋關鍵詞挖掘工具的…

基于大模型的主動脈瓣病變預測及治療方案研究報告

目錄 一、引言 1.1 研究背景 1.2 研究目的 1.3 研究意義 二、大模型預測主動脈瓣病變原理 2.1 大模型介紹 2.2 數據收集與處理 2.3 模型訓練與優化 三、術前預測與評估 3.1 主動脈瓣病變類型及程度預測 3.2 患者整體狀況評估 3.3 手術風險預測 四、術中應用與監測…

進程和內存管理

目錄 一.進程的基本信息 1.1進程的定義 1.2進程的特征 1.3進程的組成 1.4線程產生的背景 1.5線程的定義 1.6進程與線程的區別 1.7進程的類別 1.8進程的優先級 1.8.1進程優先級的概念 1.8.2PRI和NI 1.9僵尸進程 1.9.1僵尸進程的定義 1.9.2僵尸進程產生的原因 1.9…

css動態設置div寬高,calc函數

在css中使用calc函數 calc() 是 CSS 中的一種函數&#xff0c;用于動態計算長度值。它允許你在 CSS 屬性中進行數學運算&#xff0c;結合不同的單位&#xff08;如 px、%、em 等&#xff09;&#xff0c;從而創建更加靈活和響應式的布局 表達式規則 運算符&#xff1a;支持加…

飛漿PaddlePaddle 貓狗數據大戰

貓狗數據大戰 1 數據集的準備以及處理操作1.1 數據集1.2 文件解壓操作&#xff08;python&#xff09; 1.3 數據的分類1.4 創建訓練集和測試集 2 網絡構建CNN版本--DeepID 人臉識別網絡結構DeepID 與 CNN 網絡結構的差異 3 深度學習模型訓練和推理的核心設置4 制圖5 訓練6 預測…

Spring Boot后端開發全攻略:核心概念與實戰指南

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家、全棧領域優質創作者、高級開發工程師、高級信息系統項目管理師、系統架構師&#xff0c;數學與應用數學專業&#xff0c;10年以上多種混合語言開發經驗&#xff0c;從事DICOM醫學影像開發領域多年&#xff0c;熟悉DICOM協議及…

PPT助手:一款集計時、遠程控制與多屏切換于一身的PPT輔助工具

PPT助手&#xff1a;一款集計時、遠程控制與多屏切換于一身的PPT輔助工具 &#x1f4dd;&#x1f3a4; 在現代化的演講和演示中&#xff0c;如何高效地控制PPT進程、保證展示的流暢性與精準性&#xff0c;成為了每個演講者必須面對的挑戰。無論是商務匯報、學術演講&#xff0…

WEB安全--文件上傳漏洞--php偽協議的利用

一、偽協議介紹 1.1、內容 在 PHP 中&#xff0c;偽協議通常指的是一種通過特定的 URL 協議方案實現某些特殊功能或行為的方式。偽協議通常并不是標準的協議&#xff08;如 HTTP、HTTPS&#xff09;&#xff0c;而是由應用程序或開發者自定義的“偽”協議&#xff0c;用于執行…