日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java之滑动窗口详解

發布時間:2024/3/24 java 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java之滑动窗口详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

一.滑動窗口

1.什么滑動窗口

2.滑動窗口的三要素

二.找到字符串中所有字母異位詞

1.題目描述

2.問題分析?

3.代碼實現

三.字符串的排列

1.題目描述

2.問題分析

3.代碼實現

四.考試的最大困擾度

1.題目描述

2.問題分析

3.代碼實現

五.替換后的最長重復字符

1.題目描述

2.問題分析

3.代碼實現

六.盡可能使字符串相等

1.題目描述

2.問題分析

3.代碼實現

七.每種字符至少取 K 個

1.題目描述

2.問題分析

3.代碼實現


一.滑動窗口

1.什么滑動窗口

滑動窗口是通過雙指針同向移動而解決的一類問題

經常用于數組或者字符串,求其滿足條件的連續子序列或者子串,將原先需要嵌套循環問題,轉換為單循環問題,降低時間復雜度

主要分為兩大類,一種是長度固定的滑動窗口,一種是長度動態變化的滑動窗口

2.滑動窗口的三要素

我們分析問題主要就是考慮這三要素,尋找滿足題意的條件,使窗口的右端(right)可以向右滑行,滿足條件的時候,使窗口的左端(left)向右滑行,進行收縮,直到對整個數組(或字符串)線性遍歷完成

窗口擴展是尋找可行解

窗口收縮是優化可行解

窗口只能從左至右滑動

注意:長度固定的滑動窗口不需要擴張和收縮,只需要保持固定的長度向右滑動即可

二.找到字符串中所有字母異位詞

1.題目描述

給定兩個字符串?s?和 p,找到?s?中所有?p?的?異位詞?的子串,返回這些子串的起始索引。不考慮答案輸出的順序。

異位詞 指由相同字母重排列形成的字符串(包括相同的字符串)。

力扣:力扣

2.問題分析?

首先我們需要理解異位詞,其實就是含有各個字母數量和一個子串的字母數量相同,那么就可以成為異位,例如(aab)和(baa),他們的長度也是相同的,所以只需要在字符串s中找到長度和p字符串長度相同且各個字母數量相同的字符串即可.這很容易可以想象到滑動窗口,并且長度固定為p的長度的窗口

這里我們采用一個長度為26的字符數組來統計長度為p長度的滑動窗口的字母數量,和p的字符數組進行比較,相同即可加入到list數組中

3.代碼實現

public List<Integer> findAnagrams(String s, String p) {ArrayList<Integer> list = new ArrayList<>();if (p.length() > s.length())return list;int[] sCount = new int[26];int[] pCount = new int[26];for (int i = 0; i < p.length(); ++i) {pCount[p.charAt(i) - 'a']++;}for (int i = 0; i < p.length() - 1; ++i) {sCount[s.charAt(i)-'a']++;}for (int i = 0; i <= s.length() - p.length(); ++i) {sCount[s.charAt(i + p.length() - 1)-'a']++;if (Arrays.equals(sCount, pCount)) {list.add(i);}sCount[s.charAt(i)-'a']--;}return list;}

三.字符串的排列

1.題目描述

給你兩個字符串?s1?和?s2 ,寫一個函數來判斷 s2 是否包含 s1?的排列。如果是,返回 true ;否則,返回 false 。

換句話說,s1 的排列之一是 s2 的 子串

力扣: 力扣

2.問題分析

這一題和上一題大致相似,自己可以來嘗試一下,排列其實就是異位

3.代碼實現

public boolean checkInclusion(String s1, String s2) {if(s1.length()>s2.length())return false;char[] countS1 = new char[26];char[] countS2 = new char[26];for (int i = 0; i < s1.length(); ++i) {countS1[s1.charAt(i) - 'a']++;countS2[s2.charAt(i) - 'a']++;}if (Arrays.equals(countS1, countS2)) {return true;}for (int i = s1.length(); i < s2.length(); ++i) {countS2[s2.charAt(i - s1.length()) - 'a']--;countS2[s2.charAt(i) - 'a']++;if (Arrays.equals(countS1, countS2)) {return true;}}return false;}

四.考試的最大困擾度

1.題目描述

一位老師正在出一場由 n?道判斷題構成的考試,每道題的答案為 true (用 'T' 表示)或者 false (用 'F'?表示)。老師想增加學生對自己做出答案的不確定性,方法是?最大化?連續相同?結果的題數。(也就是連續出現 true 或者連續出現 false)。

給你一個字符串?answerKey?,其中?answerKey[i]?是第 i?個問題的正確結果。除此以外,還給你一個整數 k?,表示你能進行以下操作的最多次數:

  • 每次操作中,將問題的正確答案改為?'T' 或者?'F'?(也就是將 answerKey[i] 改為?'T'?或者?'F'?)。

請你返回在不超過 k?次操作的情況下,最大?連續 'T'?或者 'F'?的數目。

力扣:力扣

2.問題分析

分析了問題可以知道,這一題包含了字符串,連續T或F字符最大的字眼,因此很容易想到需要使用滑動窗口,因為不確定最大連續字符串的長度,所以這一題的窗口長度是不固定的.問題其實可以分為以下兩種情況:

第一種情況:使用k次機會將遇到的F變成T,在這種情況下使求得連續T的最大數目.

第二種情況:使用k次機會將遇到的T變成F,在這種情況下使求得連續F的最大數目.

最后只需要求得T和F連續的最大數目兩者的最大值即可

分析窗口擴張的情況:(拿求連續T長度最大)因為有k次機會,所以當窗口中F數量小于等于k的時候,這個時候窗口的right向右滑行

分析窗口收縮的情況:當窗口中F的數量大于k的時候,這個時候窗口left進行收縮,直到k的數量小于等于k的時候

滿足條件的窗口大小即為一個符合條件的連續T的長度,只需要尋找滿足條件的窗口的最大值即可.

3.代碼實現

public int maxConsecutiveAnswers(String answerKey, int k) {return Math.max(maxCount(answerKey, k, 'T'), maxCount(answerKey, k, 'F'));}public int maxCount(String answerKey, int k, char c) {int ans = 0;for (int left = 0, right = 0, sum = 0; right < answerKey.length(); ++right) {sum += answerKey.charAt(right) != c ? 1 : 0;while (sum > k) {sum -= answerKey.charAt(left) != c ? 1 : 0;left++;}ans = Math.max(ans, right - left + 1);}return ans;}

五.替換后的最長重復字符

1.題目描述

給你一個字符串 s 和一個整數 k 。你可以選擇字符串中的任一字符,并將其更改為任何其他大寫英文字符。該操作最多可執行 k 次。

在執行上述操作后,返回包含相同字母的最長子字符串的長度。

力扣:力扣

2.問題分析

這一題和上一題基本類似,上一題只包含T和F兩種字符,這一題一共26中字符(A--Z),所以要比較26次最大值,求出結果.

分析窗口擴張的情況:當窗口中不等于c字符的數量小于等于k次的時候,窗口右端right向右滑行

分析窗口收縮的情況:當窗口中不等于c字符的數量大于k次的時候,窗口左端left向右滑行,直到窗口中c字符的數量小于等于k次.

3.代碼實現

public int characterReplacement(String s, int k) {int res = 0;HashSet<Character> set = new HashSet<>();for (char c : s.toCharArray()) {set.add(c);}for (Character character : set) {res = Math.max(res, countMax(s, k, character));}return res;}public int countMax(String s, int k, char c) {int res = 0;for (int left = 0, right = 0, cnt = 0; right < s.length(); ++right) {cnt += s.charAt(right) != c ? 1 : 0;while (cnt > k) {cnt -= s.charAt(left) != c ? 1 : 0;left++;}res = Math.max(res, right - left + 1);}return res;}

做完這題可以自己去做下:1004. 最大連續1的個數 III: 力扣?? 1493. 刪掉一個元素以后全為 1 的最長子數組:力扣??

六.盡可能使字符串相等

1.題目描述

給你兩個長度相同的字符串,s 和 t。

將 s?中的第?i?個字符變到?t?中的第 i 個字符需要?|s[i] - t[i]|?的開銷(開銷可能為 0),也就是兩個字符的 ASCII 碼值的差的絕對值。

用于變更字符串的最大預算是?maxCost。在轉化字符串時,總開銷應當小于等于該預算,這也意味著字符串的轉化可能是不完全的。

如果你可以將 s 的子字符串轉化為它在 t 中對應的子字符串,則返回可以轉化的最大長度。

如果 s 中沒有子字符串可以轉化成 t 中對應的子字符串,則返回 0。

力扣: 力扣

2.問題分析

這一題雖然和上一題不一樣,但這一題更加簡單,因為很容易想到窗口擴張和收縮的條件

分析窗口擴張的情況:當遍歷到i位置的時候,所需要的預算小于等于maxCost的時候,窗口的右端可以繼續向右滑行

分析窗口收縮的情況:當遍歷到i位置的時候,所需要的預算大于maxCost的時候,窗口的右端不可以繼續向右滑行,這個時候窗口左端left收縮,直到小于maxCost

3.代碼實現

public int equalSubstring(String s, String t, int maxCost) {int res = 0;for (int left = 0, right = 0, sum = 0; right < s.length(); ++right) {sum += Math.abs(t.charAt(right) - s.charAt(right));while (sum > maxCost) {sum -= Math.abs(t.charAt(left) - s.charAt(left));left++;}res = Math.max(res, right - left + 1);}return res;}

七.每種字符至少取 K 個

1.題目描述

給你一個由字符 'a'、'b'、'c' 組成的字符串 s 和一個非負整數 k 。每分鐘,你可以選擇取走 s 最左側 還是 最右側 的那個字符。

你必須取走每種字符 至少 k 個,返回需要的 最少 分鐘數;如果無法取到,則返回 -1 。

力扣:力扣

2.問題分析

正難則反,我們不妨換一個角度考慮一下問題,問題是我們每次從左端或右端取走字符,最終使取走各k個字符'a','b','c',那么我們不妨這樣考慮:取走k個字符'a','b','c',字符串中還剩下多少個字符'a','b','c',求出長度最大的含有這樣的子串,最終最小的分鐘等于字符串的長度減去這個子串

設子串中要剩余至多cntA個'a',cntB個'b',cntC個'c'

分析窗口擴張的情況:當子串(滑動窗口)中所有字母的數量小于等于所需的數量(cntA,cntB,cntC)時候,窗口的right端向右滑行

分析窗口收縮的情況:當子串(滑動窗口)中任一個字母的數量大于所需的數量(cntA,cntB,cntC)時候,窗口的left端向左滑行,直至不符合條件

每次需要收集滿足條件的窗口的長度,尋找到最大長度的窗口,最終的答案就是字符串的長度減去滑動窗口長度的最大值

3.代碼實現

public int takeCharacters(String s, int k) {int left = 0, right = 0, length = s.length();char[] arr = s.toCharArray();int max = 0;int[] cnt = new int[3];//統計a,b,c的數量for (int i = 0; i < length; ++i) {cnt[arr[i] - 'a']++;}int cntA = cnt[0] - k, cntB = cnt[1] - k, cntC = cnt[2] - k;//分別為a,b,c可以剩下的最大數量if (cntA == 0 && cntB == 0 && cntC == 0)//此時要全部取走return length;if (cntA < 0 || cntB < 0 || cntC < 0)//剩下的數量為負的時候,說明a,b,c的數量不足k個return -1;cnt = new int[3];//每次循環統計剩下的a,b,c的數量while (right < length) {cnt[arr[right] - 'a']++;while (cnt[0] > cntA || cnt[1] > cntB || cnt[2] > cntC) {cnt[arr[left] - 'a']--;left++;//當剩下的字符串過長而不滿足條件的時候,滑動窗口左端向右移}max = Math.max(max, right - left+1);right++;//窗口的左端向右移}return length - max;}

做完這題,建議做一下1658. 將 x 減到 0 的最小操作數:力扣

總結

以上是生活随笔為你收集整理的Java之滑动窗口详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。