-
Notifications
You must be signed in to change notification settings - Fork 1
/
LeetCode-316-Remove-Duplicate-Letters.java
123 lines (104 loc) · 4.31 KB
/
LeetCode-316-Remove-Duplicate-Letters.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
class Solution {
// 1.
/*
https://leetcode.com/problems/remove-duplicate-letters/discuss/76766/Easy-to-understand-iterative-Java-solution
The basic idea is to find out the smallest result letter by letter (one letter at a time). Here is the thinking process for input "cbacdcbc":
Step 1: find out the last appeared position for each letter;
c - 7
b - 6
a - 2
d - 4
Step 2: find out the smallest index from the map in step 1 (a - 2);
Step 3: the first letter in the final result must be the smallest letter from index 0 to index 2;
Step 4: repeat step 2 to 3 to find out remaining letters.
So finally:
the smallest letter from index 0 to index 2: a
the smallest letter from index 3 to index 4: c
the smallest letter from index 4 to index 4: d
the smallest letter from index 5 to index 6: b
so the result is "acdb"
Notes:
after one letter is determined in step 3, it need to be removed from the "last appeared position map", and the same letter should be ignored in the following steps
in step 3, the beginning index of the search range should be the index of previous determined letter plus one
*/
// public String removeDuplicateLetters(String s) {
// HashMap<Character, Integer> map = new HashMap<>();
// for (int i = 0; i < s.length(); i++) {
// map.put(s.charAt(i), i);
// }
// int begin = 0, end = findMinPos(map);
// char[] res = new char[map.size()];
// int k = 0;
// while (k < res.length) {
// char minChar = 'z' + 1;
// for (int i = begin; i <= end; i++) {
// if (map.containsKey(s.charAt(i)) && s.charAt(i) < minChar) {
// minChar = s.charAt(i);
// begin = i + 1;
// }
// }
// res[k++] = minChar;
// map.remove(minChar);
// if (minChar == s.charAt(end)) end = findMinPos(map);
// }
// return new String(res);
// }
// private int findMinPos(HashMap<Character, Integer> map) {
// int min = Integer.MAX_VALUE;
// for (char key : map.keySet()) {
// min = Math.min(min, map.get(key));
// }
// return min;
// }
// Monotonic Stack
/*
Using StringBuidler as stack:
https://leetcode.com/problems/remove-duplicate-letters/discuss/76769/Java-solution-using-Stack-with-comments
*/
// public String removeDuplicateLetters(String s) {
// int[] count = new int[26];
// for (char c : s.toCharArray()) {
// count[c - 'a']++;
// }
// StringBuilder sb = new StringBuilder();
// boolean[] visited = new boolean[26];
// for (char c : s.toCharArray()) {
// count[c - 'a']--;
// if (visited[c - 'a']) continue;
// while (sb.length() > 0 && c < sb.charAt(sb.length() - 1) && count[sb.charAt(sb.length() - 1) - 'a'] != 0) {
// visited[sb.charAt(sb.length() - 1) - 'a'] = false;
// sb.deleteCharAt(sb.length() - 1);
// }
// sb.append(c);
// visited[c - 'a'] = true;
// }
// return sb.toString();
// }
// Monotonic Stack (the best solution I think)
/*
Using real stack:
https://leetcode.com/problems/remove-duplicate-letters/discuss/128235/Java-Stack
*/
public String removeDuplicateLetters(String s) {
// Build frequency array to remember how many a char is left in the string when iterate each char
int[] freq = new int[26];
for (char ch : s.toCharArray()) {
freq[ch - 'a']++;
}
Stack<Character> stack = new Stack<>();
for (char ch : s.toCharArray()) {
freq[ch - 'a']--;
if (stack.contains(ch)) continue;
while (!stack.isEmpty() && stack.peek() > ch && freq[stack.peek() - 'a'] > 0) {
stack.pop();
}
stack.push(ch);
}
// Build results from stack
StringBuilder sb = new StringBuilder();
while (!stack.isEmpty()) {
sb.insert(0, stack.pop());
}
return sb.toString();
}
}