[LeetCode] Special Binary String 特殊的二進位制字串
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
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
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; } };
類似題目:
參考資料: