[LeetCode] 1209. Remove All Adjacent Duplicates in String II 移除字符串中所有相鄰的重復字符之二



You are given a string s and an integer k, a k duplicate removal consists of choosing k adjacent and equal letters from s and removing them, causing the left and the right side of the deleted substring to concatenate together.

We repeatedly make k duplicate removals on s until we no longer can.

Return the final string after all such duplicate removals have been made. It is guaranteed that the answer is unique.

Example 1:

Input: s = "abcd", k = 2
Output: "abcd"
Explanation: There's nothing to delete.

Example 2:

Input: s = "deeedbbcccbdaa", k = 3
Output: "aa"
Explanation: First delete "eee" and "ccc", get "ddbbbdaa"
Then delete "bbb", get "dddaa"
Finally delete "ddd", get "aa"

Example 3:

Input: s = "pbbcggttciiippooaais", k = 2
Output: "ps"

Constraints:

  • 1 <= s.length <= 105
  • 2 <= k <= 104
  • s only contains lower case English letters.

這道題是之前那道 Remove All Adjacent Duplicates In String 的拓展,那道題只是讓移除相鄰的相同字母,而這道題讓移除連續k個相同的字母,規則都一樣,移除后的空位不保留,斷開的位置重新連接,則有可能繼續生成可以移除的連續字母。最直接暴力的解法就是多次掃描,每次都移除連續k個字母,然后剩下的字母組成新的字符串,再次進行掃描,但是這種方法現在超時了 Time Limit Exceeded,所以必須要用更加高效的解法。由於多次掃描可能會超時,所以要盡可能的在一次遍歷中就完成,對於已經相鄰的相同字母容易清除,斷開的連續字母怎么一次處理呢?答案是在統計的過程中及時清除連續的字母,由於只能遍歷一次,所以清除的操作可以采用字母覆蓋的形式的,則這里可以使用雙指針 Two Pointers 來操作,i指向的是清除后沒有k個連續相同字母的位置,j是當前遍歷原字符串的位置,這里還需要一個數組 cnt,其中 cnt[i] 表示字母 s[i] 連續出現的個數。i和j初始化均為0,開始遍歷字符串s,用 s[j] 來覆蓋 s[i],然后來更新 cnt[i],判斷若i大於0,且 s[i - 1] 等於 s[i],說明連續字母的個數增加了一個,用 cnt[i-1] + 1 來更新 cnt[i],否則 cnt[i] 置為1。這樣最終前字符串s的前i個字母就是最終移除后剩下的結果,直接返回即可,參見代碼如下:


解法一:

class Solution {
public:
    string removeDuplicates(string s, int k) {
        int i = 0, n = s.size();
        vector<int> cnt(n);
        for (int j = 0; j < n; ++j, ++i) {
            s[i] = s[j];
            cnt[i] = (i > 0 && s[i - 1] == s[i]) ? cnt[i - 1] + 1 : 1;
            if (cnt[i] == k) i -= k;
        }
        return s.substr(0, i);
    }
};

我們也可以使用棧來做,這里用個數組來模擬棧,棧中放一個由字符的出現和次數和該字符組成的 pair 對兒,初始化時放個 {0, '#'} 進去,是為了防止棧為空。然后開始遍歷字符串s的每個字符c,此時判斷若棧頂的 pair 對兒不是字符c,則組成的新的 pair 對兒 {1, c} 壓入棧中,否則將棧頂 pair 對兒的次數自增1,若此時正好等於k了,則將棧頂 pair 對兒移除,這樣最終的殘留部分都按順序保留在棧中了。此時就發現用數組的好處了,因為可以從開頭遍歷,按順序將剩余部分放入結果 res 中即可,參見代碼如下:


解法二:

class Solution {
public:
    string removeDuplicates(string s, int k) {
        string res;
        vector<pair<int, char>> st{{0, '#'}};
        for (char c : s) {
            if (st.back().second != c) {
                st.push_back({1, c});
            } else if (++st.back().first == k) {
                st.pop_back();
            }
        }
        for (auto &a : st) {
            res.append(a.first, a.second);
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1209


類似題目:

Remove All Adjacent Duplicates In String


參考資料:

https://leetcode.com/problems/get-equal-substrings-within-budget/

https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string-ii/discuss/392933/JavaC%2B%2BPython-Two-Pointers-and-Stack-Solution


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM