* lexicographical order - 사전식 순서 ~= abc 순
결과를 하나의 단어로 보고 사전에서 먼저 나오는 순서라고 생각하시면 될 것 같네요!
ex) "cbacdcbc" => 결과 순서: smaller << **"acdb"** < "adbc" < "adcb" < "bacd" < "badc" < "cadb" < "cbad" << larger
```java
public String removeDuplicateLetters(String s) {
Deque q = new LinkedList<>();
boolean[] isContain = new boolean['z' - 'a' + 1];
int[] cnt = new int['z' - 'a' + 1];
for (Character c : s.toCharArray()) {
if (!isContain[c - 'a']) {
q.add(c);
cnt[c - 'a']++;
} else {
if (q.getLast() < c) {
q.add(c);
cnt[c - 'a']++;
}
}
}
String res = "";
while (!q.isEmpty()) {
Character c = q.pollFirst();
if (cnt[c - 'a'] == 1) {
res += c;
}
cnt[c - 'a']--;
}
return res;
}
```
코드 풀이(재귀이용)
```java
public String removeDuplicateLetters(String s) {
Set sortedSet = getSortedString(s);
for (char c : sortedSet) {
String subStr = s.substring(s.indexOf(c));
if (sortedSet.equals(getSortedString(subStr))) {
return c + removeDuplicateLetters(subStr.replaceAll(String.valueOf(c), ""));
}
}
return "";
}
private Set getSortedString(String s) {
Set res = new TreeSet<>((c1, c2) -> c1 - c2);
for (char c : s.toCharArray()) {
res.add(c);
}
return res;
}
```
코드 풀이(스택 이용)
```java
class Solution {
public String removeDuplicateLetters(String s) {
Map counter = new HashMap<>();
Set seen = new HashSet<>();
Deque stack = new ArrayDeque<>();
char[] chars = s.toCharArray();
setCharCount(chars, counter);
for (char c : chars) {
counter.put(c, counter.get(c) - 1);
if (seen.contains(c))
continue;
while (!stack.isEmpty() && stack.peek() > c && counter.get(stack.peek()) > 0) {
seen.remove(stack.pop());
}
stack.push(c);
seen.add(c);
}
StringBuilder sb = new StringBuilder(); // 그냥 "" 와 + 연산 했을 때보다 1ms 빠름
while (!stack.isEmpty()) {
sb.append(stack.pollLast());
}
return sb.toString();
}
private void setCharCount(char[] chars, Map counter) {
for (char c : chars) {
counter.put(c, counter.getOrDefault(c, 0) + 1);
}
}
}
```
코멘트
도전 했다가 어려워서 책보고 풀어보겠습니다...
세 가지 방법으로 풀어봤는데 마지막 코드는 hashmap이 아니라 그냥 배열로 정보 담아서 풀어도 되겠더라구요! 많이 배워가네용...
Kotlin : Time: 184 ms (63.33%), Space: 37.4 MB (70.00%)
Java : Time: 2 ms (97.74%), Space: 41.5 MB (37.75%)
코드 풀이
```java
class Solution {
fun removeDuplicateLetters(s: String): String {
if (s.length <= 1) {
return s
}
val mask = getMask(s, 0)
var i = 0
var bit = 1
while (bit <= mask) {
val c = 'a' + i
if (bit and mask == bit) {
val start = s.indexOf(c)
if (mask == getMask(s, start)) {
val next = s.substring(start + 1)
.replace(c.toString(), "")
return c + removeDuplicateLetters(next)
}
}
bit = 1 shl ++i
}
return ""
}
fun getMask(s: String, start: Int): Int {
var ret = 0
for (i in start until s.length) {
ret = ret or (1 shl (s[i] - 'a'))
}
return ret
}
}
```
책 보고 다시 풀어봤습니다
```java
import java.util.ArrayDeque;
import java.util.Deque;
class Solution {
static Deque deque;
static int[] lastIndices;
static boolean[] visits;
static char[] chars;
public String removeDuplicateLetters(String s) {
init(s);
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
int index = c - 'a';
if (visits[index]) {
continue;
}
while (isPollable(i, c)) {
int pollIndex = deque.pollLast() - 'a';
visits[pollIndex] = false;
}
visits[index] = true;
deque.addLast(c);
}
StringBuilder sb = new StringBuilder(26);
while (!deque.isEmpty()) {
sb.append(deque.pollFirst());
}
return sb.toString();
}
private void init(String s) {
deque = new ArrayDeque<>(26);
lastIndices = new int[26];
visits = new boolean[26];
chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
lastIndices[chars[i] - 'a'] = i;
}
}
private boolean isPollable(int i, int c) {
return !deque.isEmpty() && deque.peekLast() > c && i < lastIndices[deque.peekLast() - 'a'];
}
}
```
코멘트
와 문제가 참 어렵네요...
기존 문자열에서 Greedy하게 다음 character를 찾고
찾은 문자를 기준으로 새로운 문자열을 만드는 방식인데
보통 subString 만드는 방식을 선호하지 않다보니까 전혀 생각을 못 했던 것 같아요
해당 character를 선택할 수 있는가? 저는 이 부분을 bitmask 방식으로 풀어봤습니다
2023.12.20 책과 예림님이 말씀해주신 lastIndex를 활용해서 풀이한 코드를 추가했습니다~
문제 링크
* lexicographical order - 사전식 순서 ~= abc 순 결과를 하나의 단어로 보고 사전에서 먼저 나오는 순서라고 생각하시면 될 것 같네요! ex) "cbacdcbc" => 결과 순서: smaller << **"acdb"** < "adbc" < "adcb" < "bacd" < "badc" < "cadb" < "cbad" << largerSmallest Lexicographical Order이 헷갈린다면?