Special binary strings are binary strings with the following two properties:
- The number of 0's is equal to the number of 1's.
- Every prefix of the binary string has at least as many 1's as 0's.
Given a special string S
, a move consists of choosing two consecutive, non-empty, special substrings of S
, and swapping them. (Two strings are consecutive if the last character of the first string is exactly one index before the first character of the second string.)
At the end of any number of moves, what is the lexicographically largest resulting string possible?
Example 1:
Input: S = "11011000" Output: "11100100" Explanation: The strings "10" [occuring at S[1]] and "1100" [at S[3]] are swapped. This is the lexicographically largest string possible after some number of swaps.
Note:
S
has length at most50
.S
is guaranteed to be a special binary string as defined above.
這道題給了我們一個特殊的二進制字符串,說是需要滿足兩個要求,一是0和1的個數要相等,二是任何一個前綴中的1的個數都要大於等於0的個數。根據壓力山大大神的帖子,其實就是一個括號字符串啊。這里的1表示左括號,0表示右括號,那么題目中的兩個限制條件其實就是限定這個括號字符串必須合法,即左右括號的個數必須相同,且左括號的個數隨時都要大於等於右括號的個數,可以參見類似的題目Valid Parenthesis String。那么這道題讓我們通過交換子字符串,生成字母順序最大的特殊字符串,注意這里交換的子字符串也必須是特殊字符串,滿足題目中給定的兩個條件,換作括號來說就是交換的子括號字符串也必須是合法的。那么我們來想什么樣的字符串是字母順序最大的呢,根據題目中的例子可以分析得出,應該是1靠前的越多越好,那么換作括號來說就是括號嵌套多的應該放在前面。比如我們分析題目中的例子:
11011000 -> (()(()))
11100100 -> ((())())
我們發現,題目中的例子中的交換操作其實是將上面的紅色部分和藍色部分交換了,因為藍色的部分嵌套的括號多,那么左括號就多,在前面的1就多,所以字母順序大。所以我們要做的就是將中間的子串分別提取出來,然后排序,再放回即可。上面的這個例子相對簡單一些,實際上上面的紅色和藍色部分完全可以更復雜,所以再給它們排序之前,其自身的順序應該已經按字母順序排好了才行,這種特點天然適合遞歸的思路,先遞歸到最里層,然后一層一層向外擴展,直至完成所有的排序。
好,下面我們來看遞歸函數的具體寫法,由於我們移動的子字符串也必須是合法的,那么我們利用檢測括號字符串合法性的一個最常用的方法,就是遇到左括號加1,遇到右括號-1,這樣得到0的時候,就是一個合法的子字符串了。我們用變量i來統計這個合法子字符串的起始位置,字符串數組v來保存這些合法的子字符串。好了,我們開始遍歷字符串S,遇到1,cnt自增1,否則自減1。當cnt為0時,我們將這個字串加入v,注意前面說過,我們需要給這個字串自身也排序,所以我們要對自身調用遞歸函數,我們不用對整個子串調用遞歸,因為字串的起始位置和結束位置是確定的,一定是1和0,我們只需對中間的調用遞歸即可,然后更新i為j+1。當我們將所有排序后的合法字串存入v中后,我們對v進行排序,將字母順序大的放前面,最后將其連為一個字符串即可,參見代碼如下:
class Solution { public: string makeLargestSpecial(string S) { int cnt = 0, i = 0; vector<string> v; string res = ""; for (int j = 0; j < S.size(); ++j) { cnt += (S[j] == '1') ? 1 : -1; if (cnt == 0) { v.push_back('1' + makeLargestSpecial(S.substr(i + 1, j - i - 1)) + '0'); i = j + 1; } } sort(v.begin(), v.end(), greater<string>()); for (int i = 0; i < v.size(); ++i) res += v[i]; return res; } };
類似題目:
參考資料:
https://leetcode.com/problems/special-binary-string/discuss/113681/7-line-c++
https://leetcode.com/problems/special-binary-string/discuss/113212/Think-of-it-as-Valid-Parentheses