diff --git a/README.md b/README.md index 0293c38..ffb2257 100644 --- a/README.md +++ b/README.md @@ -235,6 +235,7 @@ My LeetCode solutions with Chinese explanation. 我的LeetCode中文题解。 | 312 |[Burst Balloons](https://leetcode.com/problems/burst-balloons/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/312.%20Burst%20Balloons.md)|Hard| | | 313 |[Super Ugly Number](https://leetcode.com/problems/super-ugly-number/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/313.%20Super%20Ugly%20Number.md)|Medium| | | 315 |[Count of Smaller Numbers After Self](https://leetcode.com/problems/count-of-smaller-numbers-after-self/)|[C++](solutions/315.%20Count%20of%20Smaller%20Numbers%20After%20Self.md)|Hard| | +| 316 |[Remove Duplicate Letters](https://leetcode.cn/problems/remove-duplicate-letters/)|[C++](solutions/316.%20Remove%20Duplicate%20Letters.md)|Medium| | | 318 |[Maximum Product of Word Lengths](https://leetcode.com/problems/maximum-product-of-word-lengths/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/318.%20Maximum%20Product%20of%20Word%20Lengths.md)|Medium| | | 319 |[Bulb Switcher](https://leetcode.com/problems/bulb-switcher/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/319.%20Bulb%20Switcher.md)|Medium| | | 322 |[Coin Change](https://leetcode.com/problems/coin-change/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/322.%20Coin%20Change.md)|Medium| | diff --git a/solutions/316. Remove Duplicate Letters.md b/solutions/316. Remove Duplicate Letters.md new file mode 100644 index 0000000..8757add --- /dev/null +++ b/solutions/316. Remove Duplicate Letters.md @@ -0,0 +1,40 @@ +# [316. Remove Duplicate Letters](https://leetcode.cn/problems/remove-duplicate-letters/) + +# 思路 +题目有两个要求:1)每个字符只出现一次;2)字典序最小。要求1比较好办,记录下每个字符出现的次数,如果出现过就去掉即可。为了满足条件2,需要**尽可能把小字符放在前面**,所以需要找到满足 s[i]>s[i+1] 且 后面还存在字符 s[i] 的下标 i,然后去掉 s[i] 。 + +在理解这点之后,一个直观的题解思路是:对于字符串 s,从左往右遍历,找到满足条件的 s[i],去除它后得到新的字符串 s,然后不断进行这样的循环直到不存在重复字符。但是这种解法会创建大量的中间字符串,复杂度较高。由于在删除s[i]之后,下一个需要被删除的字符串只可能在之后,所以我们其实只需要遍历一次即可找到所有s[i]并将其删除,类似与单调栈,只是有一些限制条件(因为需要保留所有出现过的字符)。 + +为此,我们首先需要先遍历一遍s统计每个字符的剩余出现次数。然后维护一个初始为空的最终结果字符串stk,并遍历一遍s: +1)对于当前字符 c,如果已经在stk中,说明应该去掉c(因为有更靠前的c); +2)否则,如果stk末尾字符大于c且stk末尾字符在s后面还会出现,那应该去掉stk末尾字符,循环直至条件不成立,然后将c加入stk; + +# C++ + +```C++ +class Solution { +public: + string removeDuplicateLetters(string s) { + if(s.size() <= 1) return s; + + vectorremain(256, 0); + for(char c: s) remain[c]++; // 标记字符c剩余多少个 + + string stk; + vectorin_stk(256, false); // 是否已经在stk中 + for(char c: s){ + if(!in_stk[c]){ // 如果不在stk中 + while(!stk.empty() && stk.back() > c){ //如果c比栈顶字符小 + if(remain[stk.back()] == 0) break; // 如果后面没有栈顶字符,那么不应该pop + in_stk[stk.back()] = false; + stk.pop_back(); + } + stk.push_back(c); + in_stk[c] = true; + } + remain[c]--; + } + return stk; + } +}; +``` \ No newline at end of file