Algorithm/프로그래머스

[프로그래머스 : 코딩테스트 연습 - Swift] 영어가 싫어요

버스트 캐넌 2023. 12. 7. 23:53

글 작성에 앞서 본 블로그의 모든 게시글은 블로그 주인의 개발 일지(일기) 형태의 게시글입니다.

정보를 나누는 방식보단, 제가 했던 방식을 공유하는 식의 글이라 읽어도 제대로 이해를 못 하실 수 있거나 더 좋은 다른 방법이 존재할 수 있습니다.

이 점 양해해 주시며 본 블로그의 게시글을 읽어주시면 감사하겠습니다.

programmers

안녕하세요 버스트캐넌입니다.

 

90%도 막히는 게 없어서 (자뻑은.. 아닙니다ㅎ) 정답률 마지노선을 80 퍼로 낮췄습니다.

 

오늘은 프로그래머스 lv0 정답률 80% 영어가 싫어요 문제를 풀어보겠습니다.

 

(저도 영어가 싫어서 고른건... 아닐 겁니다.)

 

문제


문제 설명

  • 영어가 싫은 머쓱이는 영어로 표기되어 있는 숫자를 수로 바꾸려고 합니다. 
  • 문자열 numbers가 매개변수로 주어질 때, numbers를 정수로 바꿔 return 하도록 solution 함수를 완성해 주세요.

제한사항

  • numbers는 소문자로만 구성되어 있습니다.
  • numbers는 "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" 들이 공백 없이 조합되어 있습니다.
  • 1 ≤ numbers의 길이 ≤ 50
  • "zero"는 numbers의 맨 앞에 올 수 없습니다.

입출력 예

  • numbers = "onetwothreefourfivesixseveneightnine", return = 123456789
  • "onetwothreefourfivesixseveneightnine"를 숫자로 바꾼 123456789를 return 합니다.

풀이


import Foundation

func solution(_ numbers:String) -> Int64 {
     var result: String = ""
    var num = numbers
    var a = true
    
    while(a == true) {
        if num.prefix(1) == "o" {
            result += "1"
            let substring = num.dropFirst(3)
            num = String(substring)
        } else if num.prefix(2) == "tw" {
            result += "2"
            let substring = num.dropFirst(3)
            num = String(substring)
        } else if num.prefix(2) == "th" {
            result += "3"
            let substring = num.dropFirst(5)
            num = String(substring)
        } else if num.prefix(2) == "fo" {
            result += "4"
            let substring = num.dropFirst(4)
            num = String(substring)
        } else if num.prefix(2) == "fi" {
            result += "5"
            let substring = num.dropFirst(4)
            num = String(substring)
        } else if num.prefix(2) == "si" {
            result += "6"
            let substring = num.dropFirst(3)
            num = String(substring)
        } else if num.prefix(2) == "se" {
            result += "7"
            let substring = num.dropFirst(5)
            num = String(substring)
        } else if num.prefix(1) == "e" {
            result += "8"
            let substring = num.dropFirst(5)
            num = String(substring)
        } else if num.prefix(1) == "n" {
            result += "9"
            let substring = num.dropFirst(4)
            num = String(substring)
        } else if num.prefix(1) == "z" {
            result += "0"
            let substring = num.dropFirst(4)
            num = String(substring)
        }
        
        if num == "" {
            a = false
        }
    }
    return Int64(result)!
}

기본 개념


prefix(_:)

func prefix(_ maxLength: Int) -> Publishers.Output<Self>

Swift에서 String의 특정 자릿수까지의 문자만 뽑아내는 메서드입니다.

 

여기서 나온 값은 SubString 타입으로 반환되어, String으로 쓸려면 String()으로 감싸야합니다.

 

var n: String = "hello"

n.prefix(2) // 문자열 n의 2번째자리까지만 출력

간단한 예시를 들고 왔습니다.

 

n.prefix(2)를 하게 되면 문자열 n의 첫 번째와 두 번째 문자인 he가 반환됩니다.

 

SubString

Sub + String이 합쳐진 단어로, 부분 문자열이라고 합니다.

 

SubString은 String과 같은 String protocol을 준수하고 있지만, 장기저장에는 적합하지 않아, SubString을 이용하고 싶다면, 위에서 언급했듯이 String()으로 감싸주어 String 인스턴스로 변환 후 사용해야 합니다.

 

 

dropFirst(_:)

func dropFirst(_ count: Int = 1) -> Publishers.Drop<Self>

주어진 Int 값만큼 앞에서부터 요소(Element)를 제거하고 그 뒤 요소를 반환하는 메서드입니다.

 

var n: String = "hello"

n.dropFirst(2) // 처음부터 시작해서 두자리 삭제 후 나머지 반환

또 간단한 예시를 들고 왔습니다.

 

처음 두 글자인 he가 날아가고 llo가 반환되겠네요.

 

간단히 이론 공부를 하면서 더 알아본 것이 있습니다.

 

removeFirst(_:)

mutating func removeFirst(_ k: Int)

dropFirst와 비슷하게, Int 값만큼 앞에서부터 요소를 제거합니다.

 

dropFirst와의 차이점은 removeFirst는 반환을 하지 않습니다.

 

정확하진 않지만 간단하게 설명하자면, n.dropFist()는 n과, n.dropFirst() 둘 다 자체의 값을 가지고 있지만,

 

n.removeFirst()는 n값에서 빠지기 때문에, n만 값을 가지고 있다고 생각하시면 편합니다. (다시 한번 말하지만 정확한 비유는 아닙니다)

 

여담이지만, removeFirst()를 제 풀이에 가져다 쓴다면,

 

// dropFirst
if num.prefix(1) == "o" {
    result += "1"
    let substring = num.dropFirst(3)
    num = String(substring)
}

// removeFirst
if num.prefix(1) == "o" {
    result += "1"
    num.removeFirst(3)
}

 

이렇게 됩니다.

 

자세한 설명은 밑에서 하겠습니다.

 

코드 풀이


우선 저는, String을 Int로 변환? 하는 함수를 몰라서 직접 알고리즘을 짜서 풀어보려고 했습니다.

 

Dictionary를 이용하여 ["one": 1, "two": 2 ...]를 선언하고, Dictionary의 keys 값과 입력된 변수의 문자열과 같다면 Values로 바꿔주려고 했는데... 그랬는데... 결국에는 실패했습니다.

 

구현을 해보려 하는데 제가 Dictionary를 깊숙이 해본 적이 없어서 계속 알 수 없는 문법에러가 뜨더라고요.

 

그래서 생각해 본 것이 입력받은 String을 저장하고 앞자리의 단어가 특정 단어면, 예를 들어 "o"로 시작하는 영어 단어 같은 경우는 one이 유일하니 "o"로 시작한다면, "one"으로 인식하고, 아까 이론에서 살짝 배운 메서드를 사용해서 o, n, e 3글자를 없애고 result에 "1"이라고 집어넣고 마지막에 Int64로 강제 변환해서 반환할 생각이었습니다.

 

입력된 문자열이 끝날 때까지 while문으로 돌리고, 문자열이 다 끝났으면 while문을 종료시키려고 저렇게 짰습니다 하하

 

다른 사람 코드 뜯어볼 차례네요.

 

다른 사람 코드 탐구


import Foundation

var dic = ["zero" : "0", "one": "1", "two": "2", "three": "3", "four": "4", "five": "5", 
           "six": "6", "seven": "7", "eight": "8", "nine": "9"]
func solution(_ numbers:String) -> Int64 {
    var answer = numbers
    for (k, v) in dic {
        answer = String(answer.replacingOccurrences(of: k, with: v))
    }
    return Int64(answer)!
}

 

깔끔하게 Dictonary를 사용하여 코드를 푼 모습입니다.

 

Dictonary를 다시 따로 공부를 해봐야겠습니다....

 

그리고 여기서 replacingOccurrences라는 게 쓰였는데 이것도 한번 알아보죠.

 

기본 개념


 

replacingOccurrences(of: A, with: B)

 

String의 제거, 변경을 위한 메서드입니다.

 

예시를 통해 이해하는 것이 빠를 겁니다.

 

let num = "onetwo"
let numstr = num.replacingOccurrences(of: "one", with: "1")
print(numstr) // "1two"

 

"one"이라는 String이 "1"로 변경된 걸 볼 수 있습니다.

 

let num = "onetwo"
let number = num.replacingOccurrences(of: "one", with: "")
print(number) // "two"

 

with 부분을 공백으로 두어 삭제하는 것도 가능합니다.

 

이상 영어가 싫어요 문제를 풀어보았습니다.

 

포스팅 읽어주셔서 감사합니다.

 

좋은 하루 보내세요~

 

궁금한 점이나 지적해야 할 부분이 있으시면 댓글 남겨주세요. 블로그 주인의 상황에 따라 답변이 없을 수 있으나, 최대한 피드백해 드리겠습니다.