class Solution {
public boolean isValid(String s) {
if (s.length()==1) return false;
Deque<Character> stack = new ArrayDeque<Character>();
for(char c : s.toCharArray()){
if(c=='('|| c=='{'|| c=='['){
stack.push(c);
}else{
if(stack.isEmpty()) return false;
char open = stack.pop();
if(open=='(' && c!=')') return false;
if(open=='{' && c!='}') return false;
if(open=='[' && c!=']') return false;
}
}
if(!stack.isEmpty()) return false;
return true;
}
}
class Solution {
public boolean isValid(String s) {
// 홀수 길이는 무조건 false
if (s.length() % 2 != 0) return false;
Deque<Character> stack = new ArrayDeque<>();
Map<Character, Character> pairs = Map.of(
')', '(',
'}', '{',
']', '['
);
for (char c : s.toCharArray()) {
if (pairs.containsValue(c)) {
// 여는 괄호
stack.push(c);
} else {
// 닫는 괄호
if (stack.isEmpty() || stack.pop() != pairs.get(c)) {
return false;
}
}
}
return stack.isEmpty();
}
}
class Solution {
public boolean isValid(String s) {
if (s.length() % 2 != 0) return false;
Deque<Character> stack = new ArrayDeque<>();
for (char c : s.toCharArray()) {
switch (c) {
case '(': stack.push(')'); break;
case '{': stack.push('}'); break;
case '[': stack.push(']'); break;
default:
if (stack.isEmpty() || stack.pop() != c) return false;
}
}
return stack.isEmpty();
}
}
💡 Switch 방법의 핵심 아이디어: 여는 괄호를 만나면 대응되는 닫는 괄호를 push하여, 나중에 닫는 괄호를 만났을 때 단순 비교만 하면 됨!
class Solution {
public boolean isValid(String s) {
if (s.length() % 2 != 0) return false;
char[] stack = new char[s.length()];
int top = -1;
for (char c : s.toCharArray()) {
if (c == '(') stack[++top] = ')';
else if (c == '{') stack[++top] = '}';
else if (c == '[') stack[++top] = ']';
else if (top < 0 || stack[top--] != c) return false;
}
return top == -1;
}
}
| 방법 | 시간복잡도 | 공간복잡도 | Runtime | 가독성 | 추천도 |
|---|---|---|---|---|---|
| 원본 코드 | O(n) | O(n) | 2ms | ⭐⭐⭐ | ⭐⭐⭐ |
| HashMap | O(n) | O(n) | 2-3ms | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Switch | O(n) | O(n) | 1-2ms | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 배열 스택 | O(n) | O(n) | 1ms | ⭐⭐⭐ | ⭐⭐⭐⭐ |
참고: 모두 O(n) 복잡도지만, 실제 실행 시간은 상수 요인에 따라 차이 발생
스택의 활용: LIFO 구조가 괄호 매칭에 완벽하게 맞는 이유
조기 종료 최적화: 홀수 길이 체크로 불필요한 연산 방지
트레이드오프: 가독성 vs 성능
스택(Stack) 문제의 전형적인 패턴:
1. 여는 요소 → push
2. 닫는 요소 → pop하여 검증
3. 끝에 스택이 비어있어야 함
괄호 문제의 실패 조건:
추천: Switch 문 방식 (성능과 가독성의 균형)
class Solution {
public boolean isValid(String s) {
// 홀수 길이는 무조건 매칭 불가
if (s.length() % 2 != 0) return false;
Deque<Character> stack = new ArrayDeque<>();
for (char c : s.toCharArray()) {
// 여는 괄호면 대응되는 닫는 괄호를 push
switch (c) {
case '(': stack.push(')'); break;
case '{': stack.push('}'); break;
case '[': stack.push(']'); break;
// 닫는 괄호면 스택 top과 비교
default:
if (stack.isEmpty() || stack.pop() != c) {
return false;
}
}
}
// 모든 괄호가 매칭되었으면 스택이 비어있어야 함
return stack.isEmpty();
}
}
개선 포인트:
LeetCode 22. Generate Parentheses ⭐⭐⭐
LeetCode 32. Longest Valid Parentheses ⭐⭐⭐⭐⭐
LeetCode 921. Minimum Add to Make Parentheses Valid ⭐⭐
LeetCode 1249. Minimum Remove to Make Valid Parentheses ⭐⭐
LeetCode 856. Score of Parentheses ⭐⭐⭐
#Stack #Deque #BracketMatching #StringValidation #LeetCodeEasy
#ArrayDeque#HashMap #Switch #LIFO #DataStructures #Parsing
#BalancedString #TwoPointer#FastFail #EdgeCase #코딩테스트 #알고리즘
#자료구조