210825 괄호 짝꿍 찾기
문제
s는 여러 괄호들로 이루어진 String 인자입니다.
s가 유효한 표현인지 아닌지 true/false로 반환해주세요.
종류는 (
, )
, [
, ]
, {
, }
으로 총 6개 있습니다.
아래의 경우 유효합니다.
한 번 괄호를 시작했으면, 같은 괄호로 끝내야 한다.
괄호 순서가 맞아야 한다.
예를 들어 아래와 같습니다.
s = "()"
return true
s = "()[]{}"
return true
s = "(]"
return false
s = "([)]"
return false
s = "{[]}"
return true
이번에 새로 배운 개념
ADT (Abstract Data Type)
추상 자료형
어떤 데이터의 구체적인 구현 방식은 생략한 채,
데이터의 추상적 형태와 그 데이터를 다루는 방법
스택 Stack
- 데이터를 집어넣을 수 있는 선형(linear) 자료형
- LIFO(Last In First Out) : 나중에 집어넣은 데이터가 먼저 나온다
- 데이터가 들어가는 곳과 나오는 곳이 동일하다
- 데이터를 집어넣는 push
- 데이터를 추출하는 pop
- 맨 나중에 집어넣은 데이터를 확인하는 peek
큐 (Queue)
- 데이터를 집어넣을 수 있는 선형(linear) 자료형
- FIFO(First In First Out) : 먼저 집어넣은 데이터가 먼저 나온다
- 순서대로 처리해야 하는 작업을 임시로 저장해두는 버퍼(buffer)로 사용된다
- 데이터를 집어넣는 enqueue
- 데이터를 추출하는 dequeue
문제이해
따라서 데이터를 넣고 빼는 곳이 동일한 선형 자료형 stack의 배열 만들고
여는 괄호가 나오면 → push해서 데이터가 추가하고
닫는 괄호가 나오면 → pop으로 데이터를 꺼내면서 반환된 값은 배열 객체의 키값으로 지정한다
따라서 정상적인 괄호만나면 최종적으로 남는것이없다
(())()
이처럼 여는 괄호가 더 많은 경우
스택에 남게 되서 비어있지 않으면 false
(()))(
처럼 순서가 맞지 않아도
닫는괄호가 나오면 자기 짝을 pop 처리를 해줘야되는데
)
이 괄호가 나왔을 때에는 해당하는 여는괄호 (짝) 이 stack에 없기 때문에
정상적인 괄호가 아니라 false가 된다
따라서 스택의 제일 상단에 짝이 있어야 pop을 해줄 수 있다
정답
function isValid(s) {
let result = true;
let stack = [];
let map = {
'(': ')',
'[': ']',
'{': '}'
}
for (let i = 0; i < s.length; i++) {
if (s[i] === "(" || s[i] === "[" || s[i] === "{") {
stack.push(s[i]);
} else {
let s_key = stack.pop();
if (s[i] !== map[s_key])
result = false;
}
}
if (stack.length !== 0)
result = false;
return result;
}
코드설명
- isValid 함수에서 사용할 값 변수로 지정하면서 초기값 설정
- 입력한 괄호가 true인지 false인지 결과값을 담을 변수 result에 초기값으로는 true 로 설정했다
- stack 자료형의 빈 배열 stack
- 여는 괄호가 key, 닫는 괄호가 value인 객체 map
let result = true;
// 이후에는 정상적이지 않은 괄호형태만 false로 지정하도록 한다
let stack = [];
let map = {
'(': ')',
'[': ']',
'{': '}'
}
- 문자열의 처음부터 끝까지 요소를 확인할 것이기 때문에 for문 이용
for (let i = 0; i < s.length; i++) {
}
- 만약 여는 괄호가 나오면 stack 배열에 해당하는 값 push 해준다
if (s[i] === "(" || s[i] === "[" || s[i] === "{") {
stack.push(s[i]);
}
- 그렇지 않다면 (=닫는괄호가 나온다면)
- 현재 stack 배열에서 가장 바깥에 담긴 값을 s_key 라는 변수에 담고
- map 객체에서 s_key의 키값 (=닫는괄호) 이 해당하는 해당하는 괄호 (=닫는괄호)와 동일하지 않으면 정상적이지 않은 괄호형태라 result에는 false라는 값이 담긴다
예를 들어 stack 배열에는 "(" 가 있고, 해당하는 값이 "]"이라면
s_key = "("
map[s_key] = ")"
s[i] = "]"
이기 때문에 result 에는 false 값이 들어간다
else {
let s_key = stack.pop();
if (s[i] !== map[s_key])
result = false;
}
- 인자로 넣어준 문자열의 처음부터 끝까지 for문을 통해 모두 확인했을 때
stack 배열에 요소가 남아있다면 정상적인 괄호 형태가 아니므로 false가 된다
if (stack.length !== 0) result = false;
다른 정답
function isValid(s) {
let arr = s.slice();
for (let i = 0; i < s.length / 2; i++) {
for (let j = 0; j < s.length; j++) {
let match = arr[j] + arr[j + 1];
if (match === '()' || match === '{}' || match === '[]') {
arr = arr
.replace(arr[j], '')
.replace(arr[j + 1], '');
}
}
}
if (arr === '')
return true;
else
return false;
}
코드설명
- 인자로 받은 문자열을 slice() 메서드를 이용해 배열로 만들어준다
문자열에 split()을 해도 동일한 문자열인데 무슨차이일까...
arr대신에 s자체로 코드를 작성하면 틀린다고 나온다
let arr = s.slice();
- 문자 2개를 비교할 거라 for문 두개를 돌린다
- for문 2개 중 하나는 범위를
i < s.length / 2;
라고적어주는데 범위를 동일하게 s.length 라고 잡아줘도 잘 작동한다 - 찾아보지는 않았지만 내 생각에는 match가 동일한 괄호로 열고 닫아주면 두개 모두 삭제하기 때문에 굳이 처음에 비교하는 바깥의 for문의 범위를 s.length 까지 지정할 필요가 없어서인 것 같다 (속도차이)
- for문 2개 중 하나는 범위를
- i < s.length
- i < s.length / 2
for (let i = 0; i < s.length / 2; i++) {
for (let j = 0; j < s.length; j++) {}
}
- 해당하는 요소와 그 다음 요소의 값을 match 라는 변수에 담는다
let match = arr[j] + arr[j + 1];
- 만약 match가 열고 닫으면 해당하는 값과 그 다음 값은 삭제한다
if (match === '()' || match === '{}' || match === '[]') {
arr = arr
.replace(arr[j], '')
.replace(arr[j + 1], '');
}
for문을 이용해서 괄호 열고 닫는거를 세트로 삭제하고 나면
{[]}()
→ {
일 때 }
만나서 삭제 → [
일 때 ]
만나서 삭제 → (
일 때 )
만나서 삭제
- for문을 통해 문자열 s 전체를 돌았을 때
arr 배열에 요소가 남아있으면 정상적인 괄호 형식이 아니라 false가 리턴되고
arr 배열에 남아있는 요소가 없으면 정상적인 괄호형태라 true가 리턴이 된다
if (arr === '') return true;
else return false;
Author And Source
이 문제에 관하여(210825 괄호 짝꿍 찾기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@beanlove97/210825-괄호-짝꿍-찾기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)