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/