문자열을 다루다 보면 여는 괄호 (와 닫는 괄호 )가 서로 올바르게 짝을 이루고 있는지 확인해야 하는 경우가 자주 있습니다. 이번 글에서는 문자열을 입력받아 모든 여는 괄호에 대응하는 닫는 괄호가 존재하는지 검사하고, 짝이 맞으면 true, 그렇지 않으면 false를 반환하는 JavaScript 함수를 만들어 보겠습니다.
문제 정의
요구 사항은 다음과 같습니다.
- 괄호를 포함할 수 있는 문자열을 입력받는다.
- 모든 여는 괄호에 닫는 괄호가 올바른 순서로 대응하면
true를 반환한다. - 짝이 맞지 않거나 순서가 어긋나면
false를 반환한다.
예시 −
f('(hello (world))') = true
f('(hello (world)') = false접근 방법: 카운터 활용
가장 간단하고 효율적인 방법은 카운터(counter)를 사용하는 것입니다.
- 카운터를
0으로 초기화합니다. - 문자열을 한 글자씩 순회하면서 여는 괄호
(를 만나면 카운터를 증가시키고, 닫는 괄호)를 만나면 감소시킵니다. - 순회 도중 카운터가 음수가 되면, 닫는 괄호가 여는 괄호보다 먼저 나온 것이므로 즉시
false를 반환합니다. - 모든 문자를 순회한 뒤 카운터가 정확히
0이면 모든 괄호의 짝이 맞은 것이므로true를 반환하고, 그렇지 않으면false를 반환합니다.
이 방식은 시간 복잡도 O(n), 공간 복잡도 O(1)로 매우 효율적입니다.
구현 코드
다음은 위 로직을 구현한 전체 코드입니다 −
const str1 = '(hello (world))';
const str2 = '(hello (world)';
const validateBrackets = (str = '') => {
const strArr = str.split('');
let counter = 0;
for (let i = 0, len = strArr.length; i < len; i++) {
if (strArr[i] === "(") {
counter++;
} else if (strArr[i] === ")") {
counter--;
};
if (counter < 0) {
return false;
};
};
if (counter === 0) {
return true;
};
return false;
};
console.log(validateBrackets(str1));
console.log(validateBrackets(str2));실행 결과
콘솔에 출력되는 결과는 다음과 같습니다 −
true false
코드 설명
str.split('')으로 문자열을 개별 문자 배열로 변환하여 순회하기 쉽게 만듭니다.- 여는 괄호마다
counter++, 닫는 괄호마다counter--를 수행합니다. counter < 0인 순간이 있다면 닫는 괄호가 먼저 등장한 경우이므로 바로false를 반환해 불필요한 연산을 줄입니다.- 마지막에
counter === 0인지 확인하여 최종 결과를 결정합니다.
마무리
이처럼 카운터 하나만으로도 단일 종류의 괄호 짝 유효성을 손쉽게 검사할 수 있습니다. 참고로 여러 종류의 괄호((), {}, [])가 섞여 있는 경우에는 스택(stack) 자료구조를 활용하는 것이 일반적이며, 이 역시 같은 원리를 확장한 방법입니다.