올바른 괄호

김하민·2024년 12월 2일
1
post-thumbnail

문제

괄호가 바르게 짝지어졌다는 것은 '(' 문자로 열렸으면 반드시 짝지어서 ')' 문자로 닫혀야 한다는 뜻입니다. 예를 들어:

"()()" 또는 "(())()" 는 올바른 괄호입니다.
")()(" 또는 "(()(" 는 올바르지 않은 괄호입니다.

'(' 또는 ')' 로만 이루어진 문자열 s가 주어졌을 때, 문자열 s가 올바른 괄호이면 true를 return 하고, 올바르지 않은 괄호이면 false를 return 하는 solution 함수를 완성해 주세요.

링크

1차 코드 작성

import Foundation
func solution(_ s:String) -> Bool {
    
    // 첫 문자가 ")" 경우 false를 리턴
    guard s.first == "(" else { return false }
    
    var answer = false
    var stack: [Character] = []
    for char in s {
        
        switch char {
        case "(": stack.append(char)
        case ")": stack.popLast()
        default:
            answer = false
            break
        }
    }
    if stack.isEmpty {
        answer = true
    }
    return answer
}

설명이 필요하지는 않을 것 같아 생략합니다.

1트 성공

아싸

헛점발견

근데 소소한 헛점을 발견해서 고쳤습니다.

switch char {
case "(": stack.append(char)
case ")": stack.popLast()
default:
    answer = false
    break
}

저기서 answer를 false로 설정해줘도 아래의 if문에서 stack이 비었으면 answer = true가 실행되기에 고쳐줬습니다.

switch char {
case "(": stack.append(char)
case ")": stack.popLast()
default:
    return false
}

물론, 로직 상 거의 발생하지 않을 문제이지만, 소 잃고 외양간 고치는 것 보다는 미리미리 방지하는 게 낫지 않습니까?

또 다른 헛점 발견

앞에 guard문 제대로 썼나 이것저것 집어넣어보다가 이걸 발견했습니다.

"())()"

이걸 집어넣으면 false를 리턴해야 하는데 true를 리턴하네요...?

않이?

근데 왜 통과시켜줘요 프로그래머스님아

여튼 고치긴 했습니다.

고친 코드

import Foundation

func solution(_ s:String) -> Bool {

    // 첫 문자가 ")"일 경우, 또는 마지막 문자가 "(" 일 경우,
    // 무조건 닫히지 않은 괄호이니, false를 리턴
    guard s.first == "(" || s.last == ")" else { return false }

    var answer = false
    var stack: [Character] = []

    for char in s {

        switch char {
        case "(": stack.append(char)
        case ")":
            // "())()"와 같은 케이스 걸러주기 위해,
            // popLast가 nil일 경우 false를 리턴하도록 작성.
            if stack.popLast() == nil { return false }
        default: // 문자열 중 괄호 외의 문자를 발견 시 false를 리턴하도록 하는
            return false
        }
    }

    if stack.isEmpty {
        answer = true
    }

    return answer
}

결과는?

통과입니다.

아니 그래서 글자수는 왜 안 셌음?

세볼까 생각을 했는데요, 그게 생각보다 간단한 문제가 아니더라고요.
count의 시간복잡도가 O(n)이냐 O(1)이냐에 따라 다른데...

그게 자료형이 어떤 프로토콜을 따르는지에 따라 다르답니다.
이에 대해 찾아보다가 따로 글을 쓰게 되었습니다.

요약하자면, [Character]에서 .count를 쓰면, O(1)의 시간복잡도를,
String에서 .count를 쓰면 O(n)의 시간복잡도를 가진다는 내용입니다.

그니까, 어차피 for-in 반복문 쓰면 O(n)의 시간복잡도가 비용으로 지불되는데,
그 전에 굳이 또 한 번의 O(n)을 들여서 글자수를 셀 필요가 없다는 것이죠.

그래서 안 셌습니다.

0개의 댓글