이번 주부터 자료구조를 배우는데요, 오늘은 Stack과 Queue를 배웠습니다. 알고리즘 연습문제를 풀면서 겪었던 오늘의 시행착오를 적어보려고 합니다.🦁
문제 입력된 괄호 값들이 모두 쌍이 맞게 올바른지를 판단해 모두 쌍이 맞으면 true 그렇지 않으면 false를 출력하세요.
입력된 괄호 값들이 유효한 경우들은 다음에 해당합니다.
열린 괄호는 같은 타입의 닫힌 괄호로 닫혀있어야 한다.
열린 괄호는 올바른 순서대로 닫혀야만 한다.
모든 닫힌 괄호는 그에 상응하는 같은 타입의 열린 괄호를 갖고 있다.
입력값을 통해 들어오는 괄호는 ()[]{}로만 이루어져 있습니다.
실패 코드 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const isValid = (str ) => { const stack = []; if (str.length === 0 ) return false ; for (const x of str) { if (stack.length === 0 ) stack.push (x); else { if ( (stack[0 ] === '[' && x === ']' ) || (stack[0 ] === '{' && x === '}' ) || (stack[0 ] === '(' && x === ')' ) ) { stack.pop (); } else { stack.push (x); } } } return stack.length === 0 ? true : false ; };
실행결과를 보면 1개의 테스트 케이스가 실패한 것을 볼 수 있습니다.
🫥 무엇이 잘못되었을까?
테스트 케이스를 살펴보니 중첩된 괄호의 경우를 생각하지 못했습니다. 무조건 여는 괄호 다음엔 닫는 괄호가 나온다는 생각 때문에 요소를 비교할 때 stack[0]로만 제한을 두고 있습니다. 하지만 여는 괄호 다음에 여는괄호가 나올 수도 있기 때문에 0번째로만 비교해서는 안됩니다.
통과 코드 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const isValid = (str ) => { const stack = []; if (str.length === 0 ) return false ; for (let i = 0 ; i < str.length ; i++) { if (stack.length === 0 ) { stack.push (str[i]); continue ; } if ( (stack[stack.length - 1 ] === '[' && str[i] === ']' ) || (stack[stack.length - 1 ] === '(' && str[i] === ')' ) || (stack[stack.length - 1 ] === '{' && str[i] === '}' ) ) { stack.pop (); } else { stack.push (str[i]); } } return stack.length ? false : true ; };
Reference 코드 Reference Code의 Pseudo code는 다음과 같습니다.
최초 입력값이 빈 값이라면 유효하지 않은 괄호쌍으로 간주한다.
각각의 여는 괄호에 알맞는 닫는 괄호를 매칭시키기 위한 괄호맵을 생성한다.
str.length만큼 순회한다.
여는 괄호라면 stack에 push한다.
닫는괄호면 stack의 가장 마지막 요소와 그 요소에 대응하는 값을 비교한다.
같다면 stack에서 pop한다.
다르다면 false를 리턴한다.
stack이 빈 배열이라면 true를 반환하고 아니라면 false를 반환한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 const isValid = (str ) => { if (str.length === 0 ) return false ; const braketsMap = { '(' : ')' , '[' : ']' , '{' : '}' , }; const arr = str.split ('' ); const stack = []; for (let i = 0 ; i < arr.length ; ++i) { if (arr[i] === '(' || arr[i] === '[' || arr[i] === '{' ) { stack.push (arr[i]); } else { const lastElementOfStack = stack[stack.length - 1 ]; if (braketsMap[lastElementOfStack] !== arr[i]) return false ; stack.pop (); } } return stack.length ? false : true ; };
👉🏻 대응하는 값들을 객체로 선언하는 방법이 인상적이었습니다. 저렇게 객체를 만들어놓으면 if문 안에 조건을 여러 개 쓰지 않아도 되는 장점이 있는 것 같습니다. :)