Welcome to Subscribe On Youtube
316. Remove Duplicate Letters
Description
Given a string s
, remove duplicate letters so that every letter appears once and only once. You must make sure your result is the smallest in lexicographical order among all possible results.
Example 1:
Input: s = "bcabc" Output: "abc"
Example 2:
Input: s = "cbacdcbc" Output: "acdb"
Constraints:
1 <= s.length <= 104
s
consists of lowercase English letters.
Note: This question is the same as 1081: https://leetcode.com/problems/smallest-subsequence-of-distinct-characters/
Solutions
Solution 1: Stack
We use an array last
to record the last occurrence of each character, a stack to save the result string, and an array vis
or an integer variable mask
to record whether the current character is in the stack.
Traverse the string $s$, for each character $c$, if $c$ is not in the stack, we need to check whether the top element of the stack is greater than $c$. If it is greater than $c$ and the top element of the stack will appear later, we pop the top element of the stack and push $c$ into the stack.
Finally, concatenate the elements in the stack into a string and return it as the result.
The time complexity is $O(n)$, and the space complexity is $O(n)$. Where $n$ is the length of the string $s$.
-
class Solution { public String removeDuplicateLetters(String s) { int n = s.length(); int[] last = new int[26]; for (int i = 0; i < n; ++i) { last[s.charAt(i) - 'a'] = i; } Deque<Character> stk = new ArrayDeque<>(); int mask = 0; for (int i = 0; i < n; ++i) { char c = s.charAt(i); if (((mask >> (c - 'a')) & 1) == 1) { continue; } while (!stk.isEmpty() && stk.peek() > c && last[stk.peek() - 'a'] > i) { mask ^= 1 << (stk.pop() - 'a'); } stk.push(c); mask |= 1 << (c - 'a'); } StringBuilder ans = new StringBuilder(); for (char c : stk) { ans.append(c); } return ans.reverse().toString(); } }
-
class Solution { public: string removeDuplicateLetters(string s) { int n = s.size(); int last[26] = {0}; for (int i = 0; i < n; ++i) { last[s[i] - 'a'] = i; } string ans; int mask = 0; for (int i = 0; i < n; ++i) { char c = s[i]; if ((mask >> (c - 'a')) & 1) { continue; } while (!ans.empty() && ans.back() > c && last[ans.back() - 'a'] > i) { mask ^= 1 << (ans.back() - 'a'); ans.pop_back(); } ans.push_back(c); mask |= 1 << (c - 'a'); } return ans; } };
-
class Solution: def removeDuplicateLetters(self, s: str) -> str: last = {c: i for i, c in enumerate(s)} stk = [] vis = set() for i, c in enumerate(s): if c in vis: continue while stk and stk[-1] > c and last[stk[-1]] > i: vis.remove(stk.pop()) stk.append(c) vis.add(c) return ''.join(stk)
-
func removeDuplicateLetters(s string) string { last := make([]int, 26) for i, c := range s { last[c-'a'] = i } stk := []rune{} vis := make([]bool, 128) for i, c := range s { if vis[c] { continue } for len(stk) > 0 && stk[len(stk)-1] > c && last[stk[len(stk)-1]-'a'] > i { vis[stk[len(stk)-1]] = false stk = stk[:len(stk)-1] } stk = append(stk, c) vis[c] = true } return string(stk) }