2차 공부/알고리즘

괄호 회전하기

공대탈출 2024. 7. 17. 23:42

프로그래머스 - 괄호 회전하기

 

 

먼저 작성한 코드

function solution(s) {
    var answer = 0;
    let closerObj = { '[' : ']', '{' : '}', '(': ')' }
    for (let i=0; i<s.length; i++) {
        if (s.length%2 === 1) return 0;
        //괄호종류마다 닫을 필요가 있는 개수를 저장하는 객체
        let closerMap = { ']': 0, '}' : 0, ')' : 0 }
        let targetStr = s.slice(i) + s.slice(0, i)
        for (let j = 0; j<targetStr.length; j++) {
            let switchFlag = false
            let targetWord = targetStr[j]
            if (targetWord === '[') {
                closerMap[']'] = closerMap[']'] + 1
                continue;
            }
            if (targetWord === ']') {
                closerMap[']'] = closerMap[']'] - 1
                if (closerMap[']'] < 0) {
                    switchFlag = true
                    break;
                }
                continue;
            }
            if (targetWord === '{') {
                closerMap['}'] = closerMap['}'] + 1
                continue;
            }
            if (targetWord === '}') {
                closerMap['}'] = closerMap['}'] - 1
                if (closerMap['}'] < 0) {
                    switchFlag = true
                    break;
                }
                continue;
            }
            if (targetWord === '(') {
                closerMap[')'] = closerMap[')'] + 1
                continue;
            }
            if (targetWord === ')') {
                closerMap[')'] = closerMap[')'] - 1
                if (closerMap[')'] < 0) {
                    switchFlag = true
                    break;
                }
                continue;
            }
            if (switchFlag) break;
        }
        let flag = true
        //닫을필요수 객체에서 값이 0이 아닌값이 있다면 answer에 경우의수를 더하지 않는다.
        Object.keys(closerMap).forEach((key) => {
            if (closerMap[key] !== 0) {
                flag = false
            }
        })
        if (flag) {answer++};
    }
    
    return answer;
}

반복에따라 회전한 문자열 targetStr의 한 단어마다 어떤 괄호인지 검사하여 closerMap의 해당 괄호의 닫는괄호에 닫아야하는 개수를 더하거나 뺀다.

만약 타겟단어가 닫는괄호인데, 객체에서 해당 값의 1을 뺐을 때 음수라면 바로 반복을 중단하고 다음 회전으로 넘어가는 방식이었다.

14번 케이스 실패

14번은 "{(})"인 케이스이다. 괄호를 열고 닫는 순서에 대한 피드백없이 여닫는 개수만 확인하다보니 생긴 문제였다.

싹 갈아엎어야 한다. 괄호가 들어오는 순서에 대한 검사가 전혀 없기 때문이다.

 

 

두번쨰로 작성한 코드

function solution(s) {
    var answer = 0;
    
    for (let i = 0; i<s.length; i++) {
        let rotated = s.slice(i) + s.slice(0, i)
        let flag = true;
        let openClosers = [];
        
        for (const word of rotated) {
            //여는걸 배열에 순서대로 저장하고, 맨 뒤의 값을 닫는것과 비교한다.
            if (word === "[" || word === "{" || word === "(") {
                openClosers.push(word)
            } else {
                //닫는 괄호일 경우에 openClosers의 맨 마지막과 알맞는지 비교, 안맞으면 {(})이런 모양이므로 break;
                let lastOpenCloser = openClosers.pop()
                //일치할경우 다음 반복으로                
                if (lastOpenCloser === '{' && word === '}') continue;
                if (lastOpenCloser === '(' && word === ')') continue;
                if (lastOpenCloser === '[' && word === ']') continue;
                //일치하지 않을경우 flag를 false로
                flag = false
            }
        }
        //모든 글자를 돌았을 때 flag에 따라 경우를 더할지 결정
        if (flag) answer++
    }
    return answer;
}

여는괄호를 따로 배열에 순서대로 넣어두고, 닫는괄호가 나왔을 때 여는괄호배열의 제일 마지막(제일먼저 닫아야하는 괄호)와 알맞는지 판단하고 적절한 경우 다음반복으로, 아닌경우 flag를 false로 바꾼다.

이 경우 ' (){{ " 이 케이스를 잡아내지 못한다.

맨 처음 작성했을 때 음수체크하는 부분을 넣지 못한 것이다.

 

 

세번쨰로 작성한 코드

function solution(s) {
    var answer = 0;
    
    for (let i = 0; i<s.length; i++) {
        console.log(`---${i}---`)
        let backToFront = s.slice(i)
        let frontToBack = s.slice(0, i)
        // let rotated = backToFront + frontToBack
        let rotated = s.slice(i) + s.slice(0, i)
        let flag = true;
        let openClosers = [];
        
        for (const word of rotated) {
            //여는걸 배열에 순서대로 저장하고, 맨 뒤의 값을 닫는것과 비교한다.
            if (word === "[" || word === "{" || word === "(") {
                openClosers.push(word)
            } else {
                //닫는 괄호일 경우에 openClosers의 맨 마지막과 알맞는지 비교, 안맞으면 {(})이런 모양이므로 break;
                let lastOpenCloser = openClosers.pop()
                console.log('last= ', lastOpenCloser)
                console.log('targetWord= ', word)
                console.log('isFalsy= ', lastOpenCloser ? 'true' : 'false')
                //닫는괄호인데 openClosers에 아무것도 없을 때는?
                //일치할경우 다음 반복으로                
                if (!lastOpenCloser && (lastOpenCloser === '{' && word === '}')) continue;
                if (!lastOpenCloser && (lastOpenCloser === '(' && word === ')')) continue;
                if (!lastOpenCloser && (lastOpenCloser === '[' && word === ']')) continue;
                //일치하지 않을경우 flag를 false로
                flag = false
            }
        }
        // (){{
        // ){{(
        // {{()
        // {()}
        //모든 글자를 돌았을 때 flag에 따라 경우를 더할지 결정
        console.log('flag= ', flag)
        if (flag) answer++
        console.log('answer= ', answer)
        console.log(`---${i}---`)
    }
    return answer;
}

하다가 포기했다. openClosers배열이 비어있을 때 닫는 괄호가 나오면 flag를 바꾸고 break한다 라는 것을 작성하고 싶었는데 실패했다.

 

 

마지막으로 작성한 코드

function solution(s) {
    var answer = 0;
    
    if (s.length%2 === 1) return 0;
    
    //각 괄호의 여닫는 횟수가 일치하는지 확인하는 Map
    let sMap = new Map()
    sMap.set('{', 0).set('}', 0).set('[', 0).set(']', 0).set('(', 0).set(')', 0)
    for (let j = 0; j<s.length; j++) {
        sMap.set(s[j], sMap.get(s[j])+1)
    }
    if (sMap.get('{') !== sMap.get('}')) return 0;
    if (sMap.get('[') !== sMap.get(']')) return 0;
    if (sMap.get('(') !== sMap.get(')')) return 0;
    
    for (let i = 0; i<s.length; i++) {
        let rotated = s.slice(i) + s.slice(0, i)
        let flag = true;
        let openClosers = [];
        
        for (const word of rotated) {
            if (word === "[" || word === "{" || word === "(") {
                openClosers.push(word)
            } else {
                let lastOpenCloser = openClosers.pop()
                if (lastOpenCloser === '{' && word === '}') continue;
                if (lastOpenCloser === '(' && word === ')') continue;
                if (lastOpenCloser === '[' && word === ']') continue;
                flag = false
            }
        }
        if (flag) answer++
    }
    return answer;
}

각 괄호의 여닫는 개수를 저장하는 sMap을 만들어 짝지어진 괄호의 개수를 비교하고 어떤 괄호라도 맞지않으면 어떻게 회전시키더라도 완벽한 괄호를 만들어내지 못하므로 0을 리턴하는 예외처리를 해주었다.

 

성공

'2차 공부 > 알고리즘' 카테고리의 다른 글

할인 행사  (0) 2024.07.23
n^2 배열 자르기  (0) 2024.07.19
이진 변환 반복하기  (0) 2024.07.09
JadenCase 문자열 만들기  (0) 2024.07.08
최댓값과 최소값  (0) 2024.07.05