알고리즘/프로그래머스 - JS

[프로그래머스] level.2 괄호 회전하기 {stack}(**) 다른사람 풀이 너무 좋음

개발자성장기 2022. 10. 13. 03:34
반응형

https://school.programmers.co.kr/learn/courses/30/lessons/76502#

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr


나의 풀이 

function solution(s) {
    let array = s.slice()
    let result = 0 
    for(i=0; i<s.length; i++){
        while( array.length > 0){
        if(array.includes("{}")) array = array.replace(/{}/g, "")
        if(array.includes("[]")) array = array.replace(/\[]/g, "")
        if(array.includes("()")) array = array.replace(/\(\)/g, "")
        if(!array.includes("()") &&  !array.includes("[]") && !array.includes("{}")) break
        }
        if(array.length === 0 ) result++
        let save = s[0]
        s = s.slice(1)
        s += save
        array = s 
    }
    return result
}

 

() 또는 {} 또는 ()가 있을 때 빈 문자열로 바꿔주는 것을 무한반복한다. 

단 3개다 없을 시 while문은 종료가 된다. 

그리고 문자열의 길이가 0이면 카운트를 센다.  

따라서 최종적으로 왼쪽으로 s의 길이 만큼 회전시킨뒤 그 카운트를 return한다. 

while 바로위에   }  ]   ) 로 시작하거나  { [ (로 끝나면 바로 continue시켜주면 좋다. 

단 회전시키는 것도 같이해야되서 코드가 더 길어지기때문에 여기서는 하지 않았다

만약 효율성 테스트도 있다면 하는것을 무조건 추천한다. 

또한 홀수 짝수도 구분해주는 것도 좋은 방법이다. 

 

이 문제를 보고 스택으로 해야겠다고 바로 생각나지 않았다. 

 

이전 비슷한 유형문제푼게 기억났다.

 

https://html-jc.tistory.com/424

 

[프로그래머스] level.2 올바른 괄호

https://school.programmers.co.kr/learn/courses/30/lessons/12909# 프로그래머스 코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘..

html-jc.tistory.com

이 문제는 소괄호로만 해서 

function solution(s){
    let sum = 0;
    for(i=0; i<s.length; i++){
        if(sum < 0)return false;
        if(s[i] === "(") sum++;
        else sum--;
    }
    return sum ? false : true;
}

이렇게만 하면 답이나왔다.  즉 여기는 소괄호에다가 회전하는 것도 없으니 이렇게 하면된다. 

여기서는 처음에 ) 이게나오면 -1이되기때문에 바로 false가 return이 되기때문에 예외처리가 다 되었다. 

 

하지만 이 문제는 다르다.

이 문제는 소괄호, 중괄호, 대괄호 이렇게 3개가 필요하다. 

스택이 더 늘었다. 구분을 해줘야한다. 

 

function solution(s) {
  let result = 0;
  for (i = 0; i < s.length; i++) {
    let sum = 0;
    for (item of s) {
      if (s[0] === "}" || s[0] === ")" || s[0] === "]") {
        sum = -1;
      }
      if (sum < 0) break;
      if (item === "{" || item === "(" || item === "[") sum++;
      else sum--;
    }
    let save = s[0];
    s = s.slice(1);
    s += save;
    if (sum === 0) result++;
  }
  return result;
}

처음에는 이렇게 해줬다. 

이렇게하면 문제점이 

"(]{)"  이것도 정답이된다. 

구분을 꼭 해줘야한다. 

 

 

 

그래서 이번에는 구분을 해줬다. 

function solution(s) {
  let result = 0;
  let distinction;
  for (i = 0; i < s.length; i++) {
    let sum;
    let big;
    let middle;
    let small;
    for (item of s) {
      if (s.at(-1) === "{" || s.at(-1) === "[" || s.at(-1) === "(") sum = -1;
      if (s[0] === "}" || s[0] === ")" || s[0] === "]") {
        sum = -1;
      }
      if (sum < 0) break;
      if (item === "{") big === undefined ? (big = 1) : big++;
      else if (item === "[") middle === undefined ? (middle = 1) : middle++;
      else if (item === "(") small === undefined ? (small = 1) : small++;
      else if (item === "}") big === undefined ? (sum = -1) : big--;
      else if (item === "]") middle === undefined ? (sum = -1) : middle--;
      else if (item === ")") small === undefined ? (sum = -1) : small--;
    }
    if (big === 0 && middle === 0 && small === 0) distinction = true;
    let save = s[0];
    s = s.slice(1);
    s += save;
    if (distinction) {
      result++;
      distinction = false;
    }
  }
  return result;
}

이렇게 하면 42.9점을 맞는다.

14개중에 8개가 틀릴 것이다. 

스택이아니라 +1 -1 로하면 어디선가 꼬이는 것 같다. 

 

그래서 결국 전부 갈아 엎고 맨 위에있는 것 처럼 작성해줬다. 

 

 

실수한 점 

1. 논리연산자

if문에서 여러개를 할때는 아래처럼해야하는데 잘못했다. 

예전에 실수해서 써놓았는 데 그새 까먹었나보다 다시 보자.

if (s[0] === "}" || s[0] === ")" || s[0] === "]")  // 정상

if (s[0] === "}" || ")" || "]")  // 비정상

https://html-jc.tistory.com/357

 

[JS - 개념] if / switch 문에서 or 중첩 사용시 주의할 점

function monthClassify(month){ if(month == 1 || 3 || 5 || 7 || 8 || 10 || 12){ console.log(`${month}월의 날 수는 31`) }else if(month == 4 || 6 || 9 || 11){ console.log(`${month}월의 날 수는 30`) }e..

html-jc.tistory.com

 

2. 정규표현식

 

        if(array.includes("[]")) array = array.replace(/\[]/g, "")
        if(array.includes("()")) array = array.replace(/\(\)/g, "")

[]을 표현하고 싶으면 꼭 \을 써줘야한다. 

그리고 괄호는 각각 써줘야 오류가 없다. 

 

 

 


다른 사람 풀이 

 

function solution(s) {
    if(s.length % 2 === 1) return 0;

    let count = 0;
    const mapping = { "}" : "{", "]" : "[", ")" : "("};

    for(let i = 0; i < s.length; i++) {
        const stack = [];
        const rotate = s.slice(i) + s.slice(0, i);
        let flag = true;

        for(let j = 0; j < s.length; j++) {
            if(rotate[j] === "[" || rotate[j] === "(" || rotate[j] === "{" )
                stack.push(rotate[j]);
            else {
                const last = stack.pop();
                if(last !== mapping[rotate[j]]) {
                    flag = false
                    break;
                }
            }
        }

        if(flag) count++;
    }

    return count;
}

와 스택을 너무 잘 활용한 풀이 같다. 

특히 mapping이 진짜 아이디어 같다. 

 

처음에 if문은 홀수이면 바로 0을 return한다. 

하나라도 괄호가 되지않으면 소용없기때문이다. 

 

for문에서는 

rotate를 통해서  s 문자열을 계속 회전하게 만든다.  ( 이것도 진짜 아이디어다  어떻게 이렇게 할 생각을 한거지 ?)

그리고 flag가 true이면 count가 시작된다. 

이중 for문에서는  rotate된 문자열에서 하나하나 확인하는 작업을 한다. 

일단  { [ ( 이렇게 된 것을 stack에 담는다. 

만약 이게 아니라면 두 가지 경우다 

하나는  ) ] } 시작되거나 이미 스택에 담겨있는 상태에서 ) ] } 일 것이다 

전자는 바로 break될것이고 후자라면 스택 맨 뒤에서 추출한 뒤 ( 이 추출한 것은 ( { [ 중 하나일 것이다.  이게 last에 할당된다.)

이 last와   mapping[rotate[j]]이 같은지 확인 작업을 한다.   lotate[j]는  ] ) } 중 하나기에  mapping을 하면 짝이 찾아진다. ( 이건 진짜 대박)

 

그리고 같지 않을 때만 flag = false가 되고 break가 된다. 

이 과정을 다 거치면 답이 나온다. 

 

정말 코드를 잘 짠것 같다.  

 

 

 

반응형