2434 - Using a Robot to Print the Lexicographically Smallest String
정보
- 문제 보기: 2434 - Using a Robot to Print the Lexicographically Smallest String
- 소요 시간: 52분 36초
- 풀이 언어:
java
- 체감 난이도: 3️⃣~4️⃣ (3.3)
- 리뷰 횟수: ✅
풀이 키워드
스포주의
문자열
해시
그리디
풀이 코드
정보
- 메모리: 45640 KB
- 시간: 36 ms
class Solution {
public String robotWithString(String s) {
// 첫 글자를 미리 t로 init
final int n = s.length();
int[] remained = new int[26];
char[] sArr = s.toCharArray();
for (char ch : sArr) ++remained[ch-'a'];
char[] t = new char[n];
t[0] = sArr[0];
--remained[sArr[0]-'a'];
int i = 1;
int j = 1;
StringBuilder sb = new StringBuilder();
while (sb.length() < n) {
if (j < 1) {
t[j++] = sArr[i];
--remained[sArr[i++]-'a'];
}
else if (i == n) {
//System.out.println("i==n: " + t[j-1]);
sb.append(t[--j]);
}
else if (t[j-1] <= sArr[i]) { // 작거나 같음 -> 출력? 보류?
boolean smallest = true;
for (int k = t[j-1]-'a'-1; -1 < k; --k) {
if (0 < remained[k]) {
smallest = false; // 더 작은 값 발견
break;
}
}
//System.out.println("smallest: " + smallest + " " + t[j-1] + " " + sArr[i]);
if (smallest)
sb.append(t[--j]); // 출력: 지금꺼가 최선
else {
t[j++] = sArr[i]; // 보류: 미래에 더 작은 값 존재
--remained[sArr[i++]-'a'];
}
}
else {
t[j++] = sArr[i]; // 보류: 출력 후보 t[j]보다 sArr[i]가 더 작음
--remained[sArr[i++]-'a'];
}
}
return sb.toString();
}
}
풀이 해설
문자열 s를 한번 다 스캔하긴 해야 하는데, 각 문자 당 처리가 들어가면 이 되고, 이건 문자열 길이 상 어렵다.
그렇다고 으로 쉽게 해결날 작업은 아니기에, 의 알고리즘이 정답이겠거니 했다.
t[j]
는 빈공간이며 마지막으로 삽입한 문자는t[j-1]
에 있다. t는 스 택처럼 작동한다.sArr[i]
는 t에 들어갈 차례가 된 문자이다.
하단의 사고 과정으로 풀이했다.
흠 s의 앞에꺼를 떼어서 t 꽁무니에 넣고, 출력할땐 t 꽁무니꺼를 빼다 쓴다고?
👇
ok... 출력하려면 일단 s에서 빼서 t로 이동해야 하네
👇
근데 t에 넣으면 넣을수록 먼저 넣었던게 안쪽으로 밀리잖아?
👇
그러니까 t에 넣기 전에 t의 꽁무니랑 t에 넣을거랑 뭐가 더 lex small한지 판단해야겠네. 꽁무니가 더 작으면 먼저 출력해버리자
👇
아 근데 s의 나머지 문자 중에 꽁무니보다 더 small한게 있으면 여기서 출력하는게 손해구나
👇
그럼 출력 전에 현 상황에서 smallest한건지 판단하는 로직을 추가하자
👇
문자열 길이 범위가 꽤 커서 smallest 판단에 매번 순회하긴 좀 그렇고, 해시 카운터를 두는게 좋겠다
👇
만약 s 순회 끝나기도 전에 t를 다 출력해버리면 무조건 하나 떼어서 t에 주고
👇
s 순회 끝났으면 t에 남은거 쭉 출력해야지