Skip to content

Commit b272fa4

Browse files
committed
add: 프로그래머스/괄호 변환
1 parent a27dd01 commit b272fa4

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# [괄호 변환 / 60058](https://programmers.co.kr/learn/courses/30/lessons/60058?language=javascript)
2+
3+
## What
4+
5+
###### Description
6+
7+
카카오에 신입 개발자로 입사한 ****은 선배 개발자로부터 개발역량 강화를 위해 다른 개발자가 작성한 소스 코드를 분석하여 문제점을 발견하고 수정하라는 업무 과제를 받았습니다. 소스를 컴파일하여 로그를 보니 대부분 소스 코드 내 작성된 괄호가 개수는 맞지만 짝이 맞지 않은 형태로 작성되어 오류가 나는 것을 알게 되었습니다.
8+
수정해야 할 소스 파일이 너무 많아서 고민하던 콘은 소스 코드에 작성된 모든 괄호를 뽑아서 올바른 순서대로 배치된 괄호 문자열을 알려주는 프로그램을 다음과 같이 개발하려고 합니다.
9+
10+
### 용어의 정의
11+
12+
**'('****')'** 로만 이루어진 문자열이 있을 경우, '(' 의 개수와 ')' 의 개수가 같다면 이를 **`균형잡힌 괄호 문자열`**이라고 부릅니다.
13+
그리고 여기에 '('와 ')'의 괄호의 짝도 모두 맞을 경우에는 이를 **`올바른 괄호 문자열`**이라고 부릅니다.
14+
예를 들어, `"(()))("`와 같은 문자열은 균형잡힌 괄호 문자열 이지만 올바른 괄호 문자열은 아닙니다.
15+
반면에 `"(())()"`와 같은 문자열은 균형잡힌 괄호 문자열 이면서 동시에 올바른 괄호 문자열 입니다.
16+
17+
'(' 와 ')' 로만 이루어진 문자열 w가 균형잡힌 괄호 문자열 이라면 다음과 같은 과정을 통해 올바른 괄호 문자열로 변환할 수 있습니다.
18+
19+
1. 입력이 빈 문자열인 경우, 빈 문자열을 반환합니다.
20+
2. 문자열 w를 두 "균형잡힌 괄호 문자열" u, v로 분리합니다. 단, u는 "균형잡힌 괄호 문자열"로 더 이상 분리할 수 없어야 하며, v는 빈 문자열이 될 수 있습니다.
21+
3. 문자열 u가 "올바른 괄호 문자열" 이라면 문자열 v에 대해 1단계부터 다시 수행합니다.
22+
3-1. 수행한 결과 문자열을 u에 이어 붙인 후 반환합니다.
23+
4. 문자열 u가 "올바른 괄호 문자열"이 아니라면 아래 과정을 수행합니다.
24+
4-1. 빈 문자열에 첫 번째 문자로 '('를 붙입니다.
25+
4-2. 문자열 v에 대해 1단계부터 재귀적으로 수행한 결과 문자열을 이어 붙입니다.
26+
4-3. ')'를 다시 붙입니다.
27+
4-4. u의 첫 번째와 마지막 문자를 제거하고, 나머지 문자열의 괄호 방향을 뒤집어서 뒤에 붙입니다.
28+
4-5. 생성된 문자열을 반환합니다.
29+
30+
**균형잡힌 괄호 문자열** p가 매개변수로 주어질 때, 주어진 알고리즘을 수행해 **올바른 괄호 문자열**로 변환한 결과를 return 하도록 solution 함수를 완성해 주세요.
31+
32+
### 매개변수 설명
33+
34+
- p는 '(' 와 ')' 로만 이루어진 문자열이며 길이는 2 이상 1,000 이하인 짝수입니다.
35+
- 문자열 p를 이루는 '(' 와 ')' 의 개수는 항상 같습니다.
36+
- 만약 p가 이미 올바른 괄호 문자열이라면 그대로 return 하면 됩니다.
37+
38+
---
39+
40+
### 입출력 예
41+
42+
<table class="table"><thead><tr><th>p</th><th>result</th></tr></thead><tbody><tr><td><code>"(()())()"</code></td><td><code>"(()())()"</code></td></tr><tr><td><code>")("</code></td><td><code>"()"</code></td></tr><tr><td><code>"()))((()"</code></td><td><code>"()(())()"</code></td></tr></tbody></table>
43+
44+
### 입출력 예에 대한 설명
45+
46+
**입출력 예 #1**
47+
이미 올바른 괄호 문자열 입니다.
48+
49+
**입출력 예 #2**
50+
51+
- 두 문자열 u, v로 분리합니다.
52+
- u = `")("`
53+
- v = `""`
54+
- u가 올바른 괄호 문자열이 아니므로 다음과 같이 새로운 문자열을 만듭니다.
55+
- v에 대해 1단계부터 재귀적으로 수행하면 빈 문자열이 반환됩니다.
56+
- u의 앞뒤 문자를 제거하고, 나머지 문자의 괄호 방향을 뒤집으면 `""`이 됩니다.
57+
- 따라서 생성되는 문자열은 `"("` + `""` + `")"` + `""`이며, 최종적으로 `"()"`로 변환됩니다.
58+
59+
**입출력 예 #3**
60+
61+
- 두 문자열 u, v로 분리합니다.
62+
- u = `"()"`
63+
- v = `"))((()"`
64+
- 문자열 u가 올바른 괄호 문자열이므로 그대로 두고, v에 대해 재귀적으로 수행합니다.
65+
- 다시 두 문자열 u, v로 분리합니다.
66+
- u = `"))(("`
67+
- v = `"()"`
68+
- u가 올바른 괄호 문자열이 아니므로 다음과 같이 새로운 문자열을 만듭니다.
69+
- v에 대해 1단계부터 재귀적으로 수행하면 `"()"`이 반환됩니다.
70+
- u의 앞뒤 문자를 제거하고, 나머지 문자의 괄호 방향을 뒤집으면 `"()"`이 됩니다.
71+
- 따라서 생성되는 문자열은 `"("` + `"()"` + `")"` + `"()"`이며, 최종적으로 `"(())()"`를 반환합니다.
72+
- 처음에 그대로 둔 문자열에 반환된 문자열을 이어 붙이면 `"()"` + `"(())()"` = `"()(())()"`가 됩니다.
73+
74+
---
75+
76+
혼자 풀기가 막막하다면, 풀이 강의를 들어보세요 [(클릭)](https://programmers.co.kr/learn/courses/10336?utm_source=programmers&utm_medium=test_course10336&utm_campaign=course_10336)
77+
78+
> 출처: 프로그래머스 코딩 테스트 연습, https://programmers.co.kr/learn/courses/30/lessons/60058
79+
80+
## How
81+
괄호나와서 당연히 스택 쓰는줄 알고 스택을 사용에 포커스를 두고 풀려고 했는데 괄호가 한가지 종류이기도 해서 꼭 스택을 써야 풀리는 문제는 아니었다. 조건을 하나씩 옮겨야 풀리는 구현문제였다. 균형잡힌 괄호 문자열일 경우 올바른 괄호문자열로 만드는 것이 문제의 목표이다. 문제에 주어진 input을 기반으로 생각해보면 다음과 같다.
82+
83+
1. "(()))("는 균현잡힌 빈 문자열이지만 올바른 괄호문자열은 아니다. 따라서 두개의 균형잡힌 괄호 문자열 u, v로 분리가 가능하다.
84+
- u인 "(())"는 가만히 두고 v인 ")("에 대해서 재귀적으로 solution 함수를 실행한다.
85+
- 재귀호출된 상태에서 u는 ")(" v는 ""이 된다.
86+
2. u가 올바른 괄호 문자열이 아니므로 아래의과정을 수행한다.
87+
- "(" 와 ")"을 각각 앞뒤로 붙이고 중간에 v에 해당하는 부분을 재귀적으로 solution 함수 실행한 결과를 추가하여 문자열을 반환한다.
88+
89+
이런 과정을 거치게 되면 "(()))("가 "(())()"로 변화되어 반환됨을 알 수 있다. 즉 재귀적인 흐름으로 조건에 맞지 않는 부분을 조건에 맞도록 연쇄적으로 반환하도록 하면 된다. 이외에도 빈 문자열같은 예외처리 요구사항을 추가하면 문제를 해결할 수 있다.
90+
91+
## Retrospective
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
function solution(p) {
2+
let answer = '';
3+
let openBracketCount = 0;
4+
let closeBracketCount = 0;
5+
let checkString = true;
6+
7+
if (p.length === 0) {
8+
// 1
9+
return answer;
10+
}
11+
12+
for (let i = 0; i < p.length; i++) {
13+
if (p[i] === '(') {
14+
openBracketCount += 1;
15+
}
16+
if (p[i] === ')') {
17+
closeBracketCount += 1;
18+
}
19+
20+
if (openBracketCount < closeBracketCount) {
21+
checkString = false;
22+
}
23+
24+
if (openBracketCount === closeBracketCount) {
25+
if (checkString === true) {
26+
// 2, 3
27+
answer += p.slice(0, i + 1) + solution(p.slice(i + 1));
28+
29+
return answer;
30+
}
31+
32+
// 4-1,2,3
33+
answer = '(' + solution(p.slice(i + 1)) + ')';
34+
35+
// 4-4
36+
for (let j = 1; j < i; j++) {
37+
answer += p[j] === '(' ? ')' : '(';
38+
}
39+
40+
// 4-5
41+
return answer;
42+
}
43+
}
44+
}
45+
46+
test('Test case', () => {
47+
expect(solution('(()())()')).toEqual('(()())()');
48+
expect(solution(')(')).toEqual('()');
49+
expect(solution('()))((()')).toEqual('()(())()');
50+
});

0 commit comments

Comments
 (0)