제 설명
다음 규칙을 지키는 문자열을 올바른 괄호 문자열이라고 정의합니다.
(), [], {} 는 모두 올바른 괄호 문자열입니다.
만약 A가 올바른 괄호 문자열이라면, (A), [A], {A} 도 올바른 괄호 문자열입니다. 예를 들어, [] 가 올바른 괄호 문자열이므로, ([]) 도 올바른 괄호 문자열입니다.
만약 A, B가 올바른 괄호 문자열이라면, AB 도 올바른 괄호 문자열입니다. 예를 들어, {} 와 ([]) 가 올바른 괄호 문자열이므로, {}([]) 도 올바른 괄호 문자열입니다.
대괄호, 중괄호, 그리고 소괄호로 이루어진 문자열 s가 매개변수로 주어집니다. 이 s를 왼쪽으로 x (0 ≤ x < (s의 길이)) 칸만큼 회전시켰을 때 s가 올바른 괄호 문자열이 되게 하는 x의 개수를 return 하도록 solution 함수를 완성해주세요.
제한사항
s의 길이는 1 이상 1,000 이하입니다.
| 입출력 | 예 |
|---|---|
| s | result |
| "{}" | 3 |
| "}]()[{" | 2 |
| "[)(]" | 0 |
| "}}}" | 0 |
다음 표는 "{}" 를 회전시킨 모습을 나타낸 것입니다.
x s를 왼쪽으로 x칸만큼 회전 올바른 괄호 문자열?
0 "{}" O
1 "](){}[" X
2 "(){}[]" O
3 "){}[](" X
4 "{}" O
5 "}{" X
올바른 괄호 문자열이 되는 x가 3개이므로, 3을 return 해야 합니다.
다음 표는 "}]()[{" 를 회전시킨 모습을 나타낸 것입니다.
| x | s를 왼쪽으로 x칸만큼 회전 | 올바른 괄호 문자열? |
|---|---|---|
| 0 | "}]()[{" | X |
| 1 | "]()[{}" | X |
| 2 | "()[{}]" | O |
| 3 | ")[{}](" | X |
| 4 | "{}" | O |
| 5 | "{}]()[" | X |
올바른 괄호 문자열이 되는 x가 2개이므로, 2를 return 해야 합니다.
입출력 예 #3
s를 어떻게 회전하더라도 올바른 괄호 문자열을 만들 수 없으므로, 0을 return 해야 합니다.
입출력 예 #4
s를 어떻게 회전하더라도 올바른 괄호 문자열을 만들 수 없으므로, 0을 return 해야 합니다.
#include <iostream>
#include <string>
#include <stack>
using namespace std;
// 괄호 문자열이 올바른지 확인하는 함수
bool isValid(const string& s) {
stack<char> st;
for (char c : s) {
if (c == '(' || c == '[' || c == '{') {
st.push(c);
} else {
if (st.empty()) return false; // 스택이 비어있는 경우
char top = st.top();
st.pop();
if ((c == ')' && top != '(') || (c == ']' && top != '[') ||
(c == '}' && top != '{')) {
return false; // 괄호의 짝이 맞지 않는 경우
}
}
}
return st.empty(); // 스택이 비어있어야 올바른 괄호 문자열
}
// 주어진 문자열을 회전시켜 올바른 괄호 문자열이 되는 경우의 수를 찾는 함수
int solution(const string& s) {
int count = 0;
int len = s.length();
// 문자열을 회전시켜가며 올바른 괄호 문자열인지 확인
for (int i = 0; i < len; i++) {
string rotated = s.substr(i) + s.substr(0, i); // 회전된 문자열 생성
if (isValid(rotated)) count++;
}
return count;
}
int main() {
string s1 = "[](){}";
string s2 = "}][[){";
string s3 = "[)(]";
string s4 = "}}}";
cout << "Result 1: " << solution(s1) << endl; // Expected : 3
cout << "Result 2: " << solution(s2) << endl; // Expected : 2
cout << "Result 3: " << solution(s3) << endl; // Expected : 0
cout << "Result 4: " << solution(s4) << endl; // Expected : 0
return 0;
}
괄호를 비교하는 문제 같이 짝을 맞추는 식의 문제들이 종종 있는 것 같다 stack 뭔가 복잡하고 쓰기 싫어서 외면 하던 것인데 이번에는 다시한번 해보았다.
스택을 만들어서 쌓는 것이 복잡하다고 생각 했는데 단지 짝을 맞추는 문제에서 한쪽에 대한 요소들을
모두 모은 다고 생각 하니 좀 덜 부담스러웠다.
괄호의 경우에는 여는 괄호가 먼저 나와야 올바른 짝이 될 가능성이 있기 때문에 여는 괄호는 스택에 먼저 넣고 해당 여는 괄호에 대한 닫는 괄호가 다른 여는 괄호의 닫는 괄호 보다 먼저 나오지 않는지만 체크하면 된다.
예를 들어 {, [ 이런 식을 나올때 "}" 이 먼저 나오면 잘못된 괄호니까 그걸 체크하기위해서는 한쪽 즉, 여는 쪽만 스택에 넣어서 맞는 짝나오면 pop 하는 것이 다
C언어만 하다가 이런거 쓰니까 진짜 미친거 같긴하다. 사실 문제 처음보고 C로 어떻게 여러번 회전시키지가 걱정이였다 복잡하고 삽질 할것 같아서 ㅎㅎ
근데 c++에는 아래 처럼 하면된다.string rotated = s.substr(i) + s.substr(0, i); // 회전된 문자열 생성+ 로 그냥 더하면 되고 substr 함수를 쓰면 아래처럼 원하는 범위의 string 다시 반환하기 때문에 간편하다
basic_string substr(size_type __pos = 0, size_type __n = npos) const { return basic_string(*this, _M_check(__pos, "basic_string::substr"), __n); }
check 할때 여는 괄호를 스택에 담는 부분
for (char c : s) { if (c == '(' || c == '[' || c == '{') { st.push(c);닫는 괄호인 경우
else { ... if (st.empty()) return false; // 스택이 비어있는 경우 char top = st.top(); st.pop(); if ((c == ')' && top != '(') || (c == ']' && top != '[') || (c == '}' && top != '{')) { return false; // 괄호의 짝이 맞지 않는 경우 }하나라도 짝이 않맞는 경우 틀린 문자열이기 때문에 일단 top을 팝하고 그걸 현재 탐색중인 괄호와 비교하여 짝이 맞지 않으면 바로 false