[LeetCode-2696] 짝을 지우면 끝 — 이번엔 while이 아니라 if
[LeetCode-2696] 짝을 지우면 끝 — 이번엔 while이 아니라 if
스택·큐 개념과 자주 쓰는 메서드는 카테고리 총정리 글에서 다룬다.
- 문제 링크: https://leetcode.com/problems/minimum-string-length-after-removing-substrings/
- 파일 경로:
src/main/java/coding_test/스택_큐/LC2696_MinimumStringLengthAfterRemovingSubstrings.java - 난이도: Easy
문제 설명
대문자로만 이루어진 문자열 s에서 부분 문자열 "AB" 또는 "CD"를 원하는 만큼 지울 수 있다. 지우고 나면 양옆이 붙어서 새로운 "AB"/"CD"가 생길 수 있다. 만들 수 있는 가장 짧은 길이를 반환한다.
1
2
Input: s = "ABFCACDB"
Output: 2 // AB 삭제 → FCACDB → CD 삭제 → FCAB → AB 삭제 → FC
시행착오
LC1544와 같은 “붙은 짝 지우기”라 스택은 바로 떠올렸다. 그런데 바로 전에 푼 LC735의 while 패턴을 그대로 가져오면서 꼬였다.
- 첫 시도:
while로 짝을 반복 확인하고, 짝을 지우면서s를substring으로 잘랐고, 짝을 지운 뒤에도 push했고,s.length()를 반환했다. 게다가 빈 스택에서peek()을 해서 NPE. - 두 번째 시도:
if/else로 바꾸고deque.size()를 반환하도록 고쳤다. 빈 스택 문제는 맨 앞에 첫 글자를 미리 push하는 걸로 피하려 했는데, 반복문이i = 0부터 돌아 첫 글자가 두 번 들어가서 모든 답이 1씩 컸다. 그리고"ABAB"처럼 중간에 스택이 다시 비는 경우는 미리 넣어두는 걸로는 막을 수 없었다. - 최종: 미리 push를 지우고,
if조건 맨 앞에!deque.isEmpty() &&를 붙여 통과.
최종 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public int minLength(String s) {
Deque<Character> deque = new ArrayDeque<>();
for (int i = 0; i < s.length(); i++) {
if (!deque.isEmpty()
&& ((deque.peek() == 'A' && s.charAt(i) == 'B')
|| (deque.peek() == 'C' && s.charAt(i) == 'D'))) {
deque.pop();
} else {
deque.push(s.charAt(i));
}
}
return deque.size();
}
오늘 배운 내용
while인지 if인지는 “처리 후에도 지금 원소가 살아 있나?”로 정한다.
- LC735:
-5가 2를 이겨도-5는 살아 있다 → 다음 상대와 또 붙는다 →while - LC2696:
B가A와 짝이 되면B도 같이 사라진다 → 더 비교할 게 없다 →if
남은 문자열은 스택이 들고 있다. 원본 s를 자를 필요가 없다. 스택에 쌓인 것 = 지금까지 살아남은 글자, 그 개수 = 답.
빈 스택 방어는 “시작할 때 한 번”이 아니라 “매번”이다. 짝을 지우다 보면 중간에 언제든 다시 빌 수 있다.
오답노트
- 틀렸던 패턴 1: 직전 문제(735)의
while을 그대로 적용. 왜: 패턴의 모양만 기억하고 “왜 while이었는지”를 따지지 않았다. - 틀렸던 패턴 2: 빈 스택
peek()→ NPE (1544에 이어 두 번째). 왜: 짝 조건을 먼저 쓰고 방어를 나중에 생각했다. - 틀렸던 패턴 3: 첫 글자 미리 push + 반복문 0부터 → 중복.
- 다음에 떠올릴 시점:
peek()을 쓰는 순간 그 앞에!isEmpty() &&가 있는지 확인한다.
AI라면 어떻게 풀었을까
구조는 같고, 맨 위 글자를 변수에 한 번 꺼내두면 조건이 더 읽기 쉬워진다.
1
2
3
4
5
6
7
8
9
10
11
12
public int minLength(String s) {
Deque<Character> stack = new ArrayDeque<>();
for (char c : s.toCharArray()) {
char top = stack.isEmpty() ? ' ' : stack.peek();
if ((top == 'A' && c == 'B') || (top == 'C' && c == 'D')) {
stack.pop();
} else {
stack.push(c);
}
}
return stack.size();
}
빈 스택일 때 top에 짝이 될 수 없는 값(' ')을 넣어두면, 짝 조건에서 isEmpty 검사를 뺄 수 있다. peek()을 한 번만 부르니 괄호도 줄고 “맨 위(top)와 지금 글자(c)가 AB 또는 CD인가”가 그대로 읽힌다.
This post is licensed under CC BY 4.0 by the author.