美团--最长全1串
美團–最長全1串
文章目錄
- 美團--最長全1串
- 一、問題描述
- 二、分析
- 三、代碼
一、問題描述
給你一個01字符串,定義答案=該串中最長的連續(xù)1的長度,現(xiàn)在你有至多K次機會,每次機會可以將串中的某個0改成1,現(xiàn)在問最大的可能答案
- 輸入描述:
- 輸出描述:
二、分析
這道題和很多題類似:
- 力扣424. 替換后的最長重復(fù)字符:替換后的最長重復(fù)字符
- 字節(jié)-字符串翻轉(zhuǎn):字符串翻轉(zhuǎn)
這幾道題基本上是一樣的,這道題也是:力扣1004. 最大連續(xù)1的個數(shù) III:最大連續(xù)1的個數(shù)
- 首先考慮本問題的最直觀樸素的想法:枚舉出每一個子串,逐個驗證其有效性并且更新最大值。
- 這種做法的時間復(fù)雜度是O(n^3),在這一數(shù)據(jù)規(guī)模下是一定會超時的,超時的原因是做了非常多重復(fù)的驗證計算,且枚舉了非常多沒有意義的串
- 那么基于我們在這類連續(xù)子數(shù)組性質(zhì)問題的經(jīng)驗,使用雙指針(滑動窗口)會是一個非常好的想法
- 雙指針解法
- 雙指針解法的重點在于維護兩個指針:
- 設(shè)置兩個指針(表現(xiàn)為數(shù)組下標(biāo)值),左指針指向當(dāng)前子串左邊界,右指針指向當(dāng)前子串右邊界,我們通過某種方法使得左右指針之間的當(dāng)前子串符合要求:即 '0' 的數(shù)目小于等于 K
- 又:我們很容易知道,最長串一定出現(xiàn)在串內(nèi) '0' 的數(shù)目飽和(如果'0'比較多)或者最大(如果 K 比較大)的情況下,因此我們需要盡可能地把右指針右移
- 那么固定左指針時,什么情況下可以使右指針右移呢?轉(zhuǎn)化次數(shù)K有剩余 或右指針的下一位是'1'
- 如此移動右指針,即可找到每一個左指針?biāo)鶎?yīng)的最長有效串,而且右指針指向的元素的下一位一定是’0’
- 那么我們可以把每一個數(shù)組元素作為左指針,以上述方式枚舉出最長有效串,然后返回結(jié)果
- 但是還是不夠快
- 不夠快的原因還是做了重復(fù)計算,在左指針變化時,右指針從左指針處開始右移,沒有有效利用上一次操作的結(jié)果,造成了大量沒有必要的操作;那么如何避免重復(fù)計算呢?
- 我們的關(guān)鍵在于剛剛提到的“0數(shù)飽和”。即:可能成為最長串的串,它內(nèi)部'0'的數(shù)量一定是飽和或者最大的
- 那么我們可以通過某種操作來使得在左指針右移之后,我們立即就能獲得新左指針對應(yīng)的'0'數(shù)飽和串/'0'數(shù)最大串
- 首先我們考察左指針右移一位時的情況:
- 首先我們需要清楚一個事實:當(dāng)右指針到達串尾部時,左指針沒有任何必要繼續(xù)右移,因為左指針右移的話子串的長度一定會減小,并且飽和性質(zhì)無法保證
- 也就是說,左指針右移的條件是:右指針沒有觸碰串的右邊界
- 那么我們會得到一個推論:當(dāng)左指針需要右移時,串中的'0'一定是飽和的而不是最大的(“飽和”指子串中0的數(shù)目與K相等,不可以再轉(zhuǎn)化0為1;“最大”指整個串中所有的0均已被轉(zhuǎn)化為1)既飽和又最大的情況也不需要右移
- 得到這個推論,我們就可以來考慮左指針右移時的情況:
- 當(dāng)前左指針指向的元素是'0'時:當(dāng)左指針右移時子串內(nèi)的'0'數(shù)減一,為了維護其飽和性質(zhì),我們剛剛提到“右指針指向的元素的下一位一定是'0'”,所以右指針一定可以右移至少一位(如果右移之后的下一位是'1'則可以繼續(xù)右移)
- 當(dāng)前左指針指向的元素是'1'時:當(dāng)左指針右移時子串內(nèi)的'0'數(shù)不變,由于我們維護了每一個子串的飽和性質(zhì),右指針不可以右移
- 每一次左指針移動及之后右指針移動的一系列操作結(jié)束之后,更新最大值。通過以上的操作,遍歷直到右指針觸碰數(shù)組右邊界,即可得到全局的最大符合條件串的長度
- 開銷分析
- 平均漸進時間復(fù)雜度O(n)
- 漸近額外空間O(1)
三、代碼
class Solution { public:int longestOnes(vector<int>& A, int K) {//在這個實現(xiàn)中,right指的是當(dāng)前子串末尾的下一位int left(0), right(0);int max(0);while (left <= right && right < A.size()) {//如果right沒有走到結(jié)尾,并且right位置為1(可以直接++)或者//right位置為0(如果k不等于0)那么可以進行一次0-》1轉(zhuǎn)變,//繼續(xù)++)while (right < A.size() && (A[right] || K != 0)) {//如果是0,那么k的值需要--if (!A[right]) K--;right++;}//更新結(jié)果max = std::max(right - left, max);//如果left位置為1,只需要left++if (A[left]) left++;//反之代表left位置為0,那么我們需要同時++else {left++, right++;}}return max;} };總結(jié)
- 上一篇: 美团--美团骑手包裹区间分组
- 下一篇: 力扣--替换后的最长重复字符