제 설명
다음 규칙을 지키는 문자열을 올바른 괄호 문자열이라고 정의합니다.

(), [], {} 는 모두 올바른 괄호 문자열입니다.
만약 A가 올바른 괄호 문자열이라면, (A), [A], {A} 도 올바른 괄호 문자열입니다. 예를 들어, [] 가 올바른 괄호 문자열이므로, ([]) 도 올바른 괄호 문자열입니다.
만약 A, B가 올바른 괄호 문자열이라면, AB 도 올바른 괄호 문자열입니다. 예를 들어, {} 와 ([]) 가 올바른 괄호 문자열이므로, {}([]) 도 올바른 괄호 문자열입니다.
대괄호, 중괄호, 그리고 소괄호로 이루어진 문자열 s가 매개변수로 주어집니다. 이 s를 왼쪽으로 x (0 ≤ x < (s의 길이)) 칸만큼 회전시켰을 때 s가 올바른 괄호 문자열이 되게 하는 x의 개수를 return 하도록 solution 함수를 완성해주세요.

제한사항
s의 길이는 1 이상 1,000 이하입니다.

입출력
sresult
"{}"3
"}]()[{"2
"[)(]"0
"}}}"0

입출력 예 설명

입출력 예 #1

다음 표는 "{}" 를 회전시킨 모습을 나타낸 것입니다.
x s를 왼쪽으로 x칸만큼 회전 올바른 괄호 문자열?
0 "{}" O
1 "](){}[" X
2 "(){}[]" O
3 "){}[](" X
4 "{}" O
5 "}{" X
올바른 괄호 문자열이 되는 x가 3개이므로, 3을 return 해야 합니다.

입출력 예 #2

다음 표는 "}]()[{" 를 회전시킨 모습을 나타낸 것입니다.

xs를 왼쪽으로 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 해야 합니다.


풀이 C++

#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 뭔가 복잡하고 쓰기 싫어서 외면 하던 것인데 이번에는 다시한번 해보았다.

1.아이디어

스택을 만들어서 쌓는 것이 복잡하다고 생각 했는데 단지 짝을 맞추는 문제에서 한쪽에 대한 요소들을
모두 모은 다고 생각 하니 좀 덜 부담스러웠다.

괄호의 경우에는 여는 괄호가 먼저 나와야 올바른 짝이 될 가능성이 있기 때문에 여는 괄호는 스택에 먼저 넣고 해당 여는 괄호에 대한 닫는 괄호가 다른 여는 괄호의 닫는 괄호 보다 먼저 나오지 않는지만 체크하면 된다.
예를 들어 {,   [ 이런 식을 나올때   "}" 이 먼저 나오면 잘못된 괄호니까 그걸 체크하기위해서는 한쪽 즉, 여는 쪽만 스택에 넣어서 맞는 짝나오면 pop 하는 것이 다

2. 회전된 배열 만들기

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); }

3. validation check

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

0개의 댓글