코딩테스트 스택 풀이: 괄호문자 제거하기

··설명 약 7분·작성: 해비·블로그 소개

읽기 전에 알아두면 좋아요

아래 개념이 익숙하면 본문을 바로 읽으세요. 낯선 개념만 링크에서 복습하면 됩니다.

개념과 예제는 실행하지 않아도 읽을 수 있습니다. 내 컴퓨터·터미널에서 직접 실행하는 과정은 선택 실습입니다.

과정 위치와 선택 복습 안내

과정 위치: 자료구조 개념과 문제 · 문제

과정 위치는 이 글이 속한 묶음입니다. 이 단계의 모든 개념을 먼저 읽을 필요는 없습니다. 위에 연결한 개념 중 낯선 내용만 복습하세요. 문제의 조건·상태·갱신 순서는 익숙한 언어로 설명하면 됩니다.

JavaScript로 문법·실행 복습하기 (선택)

개념 글의 코드는 JavaScript 예시입니다. 문제 화면에서는 JavaScript·Python·Java·C++·C# 중 익숙한 언어의 함수를 작성하세요. 본문의 Node.js 입출력 예시는 로컬 실행을 위한 별도 안내입니다.

괄호문자 제거 문제에서는 문자열에서 어떤 부분을 제외한 결과를 반환하나요?

문자열에서 괄호와 괄호 안의 문자를 제외한 결과를 반환하는 문제입니다. 문자열·반복문·스택의 기본을 준비하고, 아래 입력·반환 계약을 확인해 직접 풀어보세요.

적용 조건·범위: 중첩 소괄호 안의 문자를 제거하는 문제에서 카운터와 스택 중 무엇을 선택할지 헷갈리는 JavaScript 학습자를 위한 풀이입니다. 유효한 괄호 입력이라는 전제, 스택이 빌 때의 안전 장치, 시간·공간 복잡도와 실제 검증 케이스까지 비교해 재사용 가능한 기준을 만듭니다.

본문 근거: MDN push() · pop() 문서

문제

코딩테스트 JS 스택 풀이: 괄호문자 제거하기 전반부 흐름 정리

입력된 문자열에서 소괄호 ( ) 사이에 존재하는 모든 문자를 제거하고 남은 문자만 출력하는 프로그램을 작성하세요.

입력설명
첫 줄에 문자열이 주어진다. 문자열의 길이는 100을 넘지 않는다.

출력설명
남은 문자만 출력한다.

입력예제 1
(A(BC)D)EF(G(H)(IJ)K)LM(N)

출력예제 1
EFLM

직접 풀어보기

먼저 선택한 언어의 입력·반환 계약에 맞춰 작성해 보세요. 힌트 받기와 정답과 비교하기는 코드를 실행하지 않는 AI 분석입니다. 해답·해설은 아래에서 필요할 때 펼칠 수 있습니다.

0 / 6,000바이트

solution(s)에 s(문자열)를 전달하고 문자열를 반환합니다. 아래 문제의 유효 입력 조건을 따릅니다. 표준 입력과 출력 코드는 작성하지 않습니다. Tab은 다음 항목으로 이동합니다. 입력 영역 오른쪽 아래를 끌어 높이를 조절할 수 있습니다.

비밀키·개인정보는 입력하지 마세요. 코드는 이 페이지에만 유지됩니다.

해답·해설 보기
JavaScript 해답
function solution(s) {
    const stack = [];
    for (const ch of s) {
        if (ch !== ")") {
            stack.push(ch);
            continue;
        }
        while (stack.length && stack[stack.length - 1] !== "(") stack.pop();
        if (! stack.length) throw new Error("대응하는 여는 괄호가 없습니다.");
        stack.pop();
    }
    if (stack.includes("(")) throw new Error("닫히지 않은 괄호가 있습니다.");
    return stack.join("");
}

solution(s)에 s(문자열)를 전달하고 문자열를 반환합니다. 아래 문제의 유효 입력 조건을 따릅니다. 표준 입력과 출력 코드는 작성하지 않습니다.

내가 푼 풀이

내가 푼 풀이는 괄호문자제거 문제를 “현재 문자가 괄호 안에 있는지, 괄호 밖에 있는지”라는 상태 판단 문제로 해석한 방식입니다. 이 풀이는 스택 자료구조를 사용하지 않고, 괄호의 개수를 세는 카운트 변수 하나로 문제를 해결합니다.

문자열을 왼쪽부터 오른쪽으로 하나씩 순회하면서, 여는 괄호 ‘(‘를 만나면 카운트를 증가시키고 닫는 괄호 ‘)’를 만나면 카운트를 감소시킵니다. 카운트 값이 0이라는 의미는 현재 위치가 괄호 밖이라는 뜻이며, 이때만 문자를 결과 배열에 추가합니다.

반대로 카운트 값이 1 이상이라면 현재 문자는 괄호 내부에 있으므로 무시됩니다. 이 방식은 중첩 괄호가 몇 단계로 들어가더라도 카운트 값만 정확히 관리되면 문제없이 동작합니다.

function solution(s) {
    let answer = [];
    let count = 0;
    for (let x of s) {
        if (x === "(") {
            count++;
        } else if (x === ")" && count > 0) {
            count--;
        } else if (count === 0) {
            answer.push(x);
        }
    }
    return answer.join('');
}

let str = "(A(BC)D)EF(G(H)(IJ)K)LM(N)";
console.log(solution(str));

이 풀이의 가장 큰 장점은 코드가 매우 간결하고 직관적이라는 점입니다. 스택을 사용하지 않기 때문에 메모리 사용이 최소화되며, 문자열을 한 번만 순회하므로 시간 복잡도 또한 O(N)으로 효율적입니다.

다만 이 방식은 괄호 구조 자체를 명시적으로 표현하지 않기 때문에, 괄호 내부의 실제 문자 구성이 중요한 문제에는 그대로 적용하기 어렵다는 한계가 있습니다.

해답

코딩테스트 JS 스택 풀이: 괄호문자 제거하기 후반부 흐름 정리

정답 풀이는 괄호문자제거 문제를 스택(Stack)을 활용한 전형적인 문자열 처리 문제로 접근합니다. 이 방식은 괄호 구조를 직접 자료구조로 표현하며, 괄호 내부 문자를 실제로 제거하는 과정을 거칩니다.

문자열을 순회하면서 문자를 하나씩 스택에 저장하다가, 닫는 괄호 ‘)’를 만나면 여는 괄호 ‘(‘가 나올 때까지 스택에서 문자를 제거합니다. 이 과정에서 괄호 내부에 있던 문자와 괄호 자체가 모두 제거됩니다.

모든 문자열 처리가 끝난 후, 스택에 남아 있는 문자들만 이어 붙이면 괄호 밖 문자만으로 구성된 최종 문자열을 얻을 수 있습니다.

function solution(s) {
    const stack = [];

    for (const x of s) {
        if (x !== ')') {
            stack.push(x);
            continue;
        }

        while (stack.length > 0 && stack[stack.length - 1] !== '(') {
            stack.pop();
        }
        if (stack.length === 0) {
            throw new Error('대응하는 여는 괄호가 없습니다.');
        }
        stack.pop();
    }

    if (stack.includes('(')) {
        throw new Error('닫히지 않은 여는 괄호가 있습니다.');
    }
    return stack.join('');
}

let str = "(A(BC)D)EF(G(H)(IJ)K)LM(N)";
console.log(solution(str));

이 풀이는 괄호문제 전반에 매우 강력하게 적용할 수 있는 구조입니다. 중첩 괄호, 문자열 압축, 수식 계산 등 다양한 유형으로 확장이 가능하며, 괄호 문제의 정석적인 사고 방식을 학습하는 데 큰 도움이 됩니다.

풀이 방법 비교

두 풀이는 모두 괄호문자제거 문제를 해결할 수 있으며, 시간 복잡도는 O(N)으로 동일합니다. 그러나 문제를 바라보는 관점과 코드의 성격에는 분명한 차이가 있습니다.

구분 특징
카운트 방식 간결한 코드, 낮은 메모리 사용, 빠른 구현
스택 방식 괄호 구조 명확, 다양한 문제로 확장 가능

카운트 방식은 괄호 내부 여부만 판단하면 되는 문제에서 매우 효율적이며, 스택 방식은 괄호 구조 자체를 다뤄야 하는 문제에서 강력합니다.

어떤 풀이가 더 좋은가

코딩 테스트 관점에서는 문제의 의도를 빠르게 파악하는 것이 중요합니다. 괄호문자제거처럼 단순히 괄호 내부를 제거하는 문제라면 카운트 방식이 더 빠르고 깔끔한 선택이 될 수 있습니다.

반면 괄호의 짝 검증, 중첩 구조 분석, 수식 계산 등으로 확장될 가능성이 있다면 스택 풀이를 선택하는 것이 장기적으로 더 좋은 판단입니다.

학습 목적이라면 두 방식을 모두 이해하고, 문제 유형에 따라 적절한 접근 방식을 선택할 수 있는 판단력을 기르는 것이 가장 중요합니다.

괄호 판단을 넓히려면 JavaScript 올바른 괄호 스택 검증으로도 이어서 봐두면 도움이 됩니다.

괄호 구조 해석을 더 확장하려면 JS 쇠막대기 스택 레이저 절단 문제도 함께 비교해보세요.

유효 입력·복잡도·안전성 검증

카운터 풀이는 현재 깊이가 0일 때만 문자를 결과에 넣으므로 추가 작업 공간이 결과 배열을 제외하면 O(1)입니다. 스택 풀이는 괄호 밖 문자까지 보관하므로 최악 O(N)의 공간을 사용합니다. 두 방식 모두 각 문자를 넣고 빼는 횟수가 제한되어 전체 시간은 O(N)입니다.

기존의 while (stack.pop() !== '('); 형태는 닫는 괄호에 대응하는 여는 괄호가 없으면 pop()이 계속 undefined를 반환해 종료하지 않습니다. 수정 코드에는 스택 길이 검사를 넣고, 잘못된 입력이면 조용히 결과를 만들지 않고 오류를 내도록 했습니다. 배열 끝에 값을 넣는 push()와 마지막 값을 제거해 반환하는 pop()의 정확한 동작은 MDN push()와 pop() 문서를 기준으로 확인할 수 있습니다.

console.assert(solution('(A(BC)D)EF') === 'EF');
console.assert(solution('ABC') === 'ABC');
// solution('A)B')는 대응하는 여는 괄호가 없어 오류를 냅니다.

문제에서 항상 올바른 괄호 문자열만 준다면 간단한 카운터 풀이로 충분합니다. 입력 유효성까지 책임지는 함수라면 닫는 괄호에서 깊이가 음수가 되는지, 순회가 끝난 뒤 깊이가 0인지도 검사해야 합니다.

정리: ‘괄호 안 문자를 버린다’는 목적에는 카운터가 간단하고, 실제 문자를 되돌아가며 제거하거나 여러 구조로 확장할 때는 스택이 유용합니다. 어느 쪽이든 입력 전제와 실패 동작을 먼저 문서화하세요.

FAQ

Q. 괄호가 여러 단계로 중첩되어도 카운트 방식이 안전한가요?
네, 괄호가 올바른 순서로 짝지어진 입력이면 중첩 깊이를 카운터로 추적할 수 있습니다. 총개수만 같아서는 충분하지 않습니다. 어느 접두 구간에서도 닫는 괄호가 여는 괄호보다 많지 않고, 끝에서 깊이가 0이어야 합니다. 앞의 카운터 코드는 이 유효성을 직접 검사하지 않는다는 점도 구분하세요.

Q. 스택 방식이 더 많이 사용되는 이유는 무엇인가요?
괄호 관련 문제 대부분이 스택 구조로 일반화할 수 있기 때문에, 다양한 유형에 재사용할 수 있다는 장점이 있습니다.

Q. 실무 코드에서도 이런 풀이가 사용되나요?
실무에서는 문자열 파싱, 수식 처리, 템플릿 엔진 구현 등에서 유사한 개념이 활용되며, 특히 스택 사고 방식은 매우 중요하게 사용됩니다.

이 문제를 푼 뒤 확인하기

중첩 괄호 안의 문자가 제거되는지와 괄호 밖 문자의 순서가 유지되는지 확인해 보세요.

본문의 예제와 이 반례를 직접 실행해 예상 출력과 비교하고, 결과가 다르면 입력 조건과 반복 범위를 다시 확인하세요.

풀이 함수를 독립 실행해 확인합니다

선수 지식은 배열·조건문·반복문과 위에서 설명한 자료구조입니다. 해답의 완성 함수 블록 하나를 solution.cjs로 저장하고, 그 아래에 다음 호출을 붙입니다. 앞의 비교용 풀이와 같은 이름의 함수를 함께 붙이지 않습니다. 터미널에서 node solution.cjs로 실행합니다.

console.log(JSON.stringify(solution(...["(A)"])));

이 변형 호출의 JSON 출력은 ""입니다. 기존 함수 블록의 console.log가 있으면 그 출력 다음 줄에서 확인합니다.

글 소개·학습 준비·전체 목차

주요 포인트 한눈에 보기

중첩 소괄호 안의 문자를 제거하는 문제에서 카운터와 스택 중 무엇을 선택할지 헷갈리는 JavaScript 학습자를 위한 풀이입니다. 유효한 괄호 입력이라는 전제, 스택이 빌 때의 안전 장치, 시간·공간 복잡도와 실제 검증 케이스까지 비교해 재사용 가능한 기준을 만듭니다.

이 글이 도움이 되었나요?

조회 중

이어서 공부하기

체크포인트: 해설을 가리고 다시 풀고, 경계 입력을 하나 바꾸어 예상 결과와 실제 결과를 비교하세요. 삽입·제거 전후의 상태를 그리고, 내장 도구를 쓰는 풀이와 직접 구현의 목적을 구분하세요.

다음 추천 · 문제: 코딩테스트 스택 풀이: 크레인 인형뽑기 처리법

같은 주제의 문제에 적용하며 방금 배운 개념을 확인합니다.

권장 순서는 학습 가이드와 같습니다. 다른 순서는 접힌 참고 목록에서 확인할 수 있습니다. 읽음 표시는 숙달이나 채점 결과가 아닙니다.

원래 과정 목록 순서 (선택)

읽음 기록

읽음 — / 전체 58개 · 필수 58개

이 글을 쓴 해비

웹사이트를 제작·운영하고, 개인 서비스와 자동화·AI 도구를 만듭니다. 직접 만들며 배운 내용과 문제 해결 과정을 BlogFlow에 기록합니다.

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기