A string of `'0'`s and `'1'`s is *monotone increasing* if it consists of some number of `'0'`s (possibly 0), followed by some number of `'1'`s (also possibly 0.)
We are given a string S
of '0'
s and '1'
s, and we may flip any '0'
to a '1'
or a '1'
to a '0'
.
Return the minimum number of flips to make S
monotone increasing.
Example 1:
Input: "00110"
Output: 1
Explanation: We flip the last digit to get 00111.
Example 2:
Input: "010110"
Output: 2
Explanation: We flip to get 011111, or alternatively 000111.
Example 3:
Input: "00011000"
Output: 2
Explanation: We flip to get 00000000.
Note:
1 <= S.length <= 20000
S
only consists of'0'
and'1'
characters.
這道題給了我們一個只有0和1的字符串,現在說是可以將任意位置的數翻轉,即0變為1,或者1變為0,讓組成一個單調遞增的序列,即0必須都在1的前面,博主剛開始想的策略比較直接,就是使用雙指針分別指向開頭和結尾,開頭的指針先跳過連續的0,末尾的指針向前跳過連續的1,然后在中間的位置分別記錄0和1的個數,返回其中較小的那個。這種思路乍看上去沒什么問題,但是實際上是有問題的,比如對於這個例子 "10011111110010111011",如果按這種思路的話,就應該將所有的0變為1,從而返回6,但實際上更優的解法是將第一個1變為0,將后4個0變為1即可,最終可以返回5,這說明了之前的解法是不正確的。這道題可以用動態規划 Dynamic Programming 來做,需要使用兩個 dp 數組,其中 cnt1[i] 表示將范圍是 [0, i-1] 的子串內最小的將1轉為0的個數,從而形成單調字符串。同理,cnt0[j] 表示將范圍是 [j, n-1] 的子串內最小的將0轉為1的個數,從而形成單調字符串。這樣最終在某個位置使得 cnt0[i]+cnt1[i] 最小的時候,就是變為單調串的最優解,這樣就可以完美的解決上面的例子,子串 "100" 的最優解是將1變為0,而后面的 "11111110010111011" 的最優解是將4個0變為1,總共加起來就是5,參見代碼如下:
解法一:
class Solution {
public:
int minFlipsMonoIncr(string S) {
int n = S.size(), res = INT_MAX;
vector<int> cnt1(n + 1), cnt0(n + 1);
for (int i = 1, j = n - 1; j >= 0; ++i, --j) {
cnt1[i] += cnt1[i - 1] + (S[i - 1] == '0' ? 0 : 1);
cnt0[j] += cnt0[j + 1] + (S[j] == '1' ? 0 : 1);
}
for (int i = 0; i <= n; ++i) res = min(res, cnt1[i] + cnt0[i]);
return res;
}
};
我們可以進一步優化一下空間復雜度,用一個變量 cnt1 來記錄當前位置時1出現的次數,同時 res 表示使到當前位置的子串變為單調串的翻轉次數,用來記錄0的個數,因為遇到0就翻1一定可以組成單調串,但不一定是最優解,每次都要和 cnt1 比較以下,若 cnt1 較小,就將 res 更新為 cnt1,此時保證了到當前位置的子串變為單調串的翻轉次數最少,並不關心到底是把0變為1,還是1變為0了,其實核心思想跟上面的解法很相近,參見代碼如下:
解法二:
class Solution {
public:
int minFlipsMonoIncr(string S) {
int n = S.size(), res = 0, cnt1 = 0;
for (int i = 0; i < n; ++i) {
(S[i] == '0') ? ++res : ++cnt1;
res = min(res, cnt1);
}
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/926
參考資料:
https://leetcode.com/problems/flip-string-to-monotone-increasing/
[LeetCode All in One 題目講解匯總(持續更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)