[Swift] [3일차]이진 변환 및 replacingOccurrences

·2024년 12월 9일
0

SwiftAlgorithm

목록 보기
5/105

프로그래머스 문제 - 이진변환 반복하기

문제 설명
0과 1로 이루어진 어떤 문자열 x에 대한 이진 변환을 다음과 같이 정의합니다.
x의 모든 0을 제거합니다.
x의 길이를 c라고 하면, x를 "c를 2진법으로 표현한 문자열"로 바꿉니다.
예를 들어, x = "0111010"이라면, x에 이진 변환을 가하면 x = "0111010" -> "1111" -> "100" 이 됩니다.
0과 1로 이루어진 문자열 s가 매개변수로 주어집니다. s가 "1"이 될 때까지 계속해서 s에 이진 변환을 가했을 때, 이진 변환의 횟수와 변환 과정에서 제거된 모든 0의 개수를 각각 배열에 담아 return 하도록 solution 함수를 완성해주세요.

요약

그니까 이진수로 주어지는 문자열을
1. 이진수에서 0 제거
2. 그 제거한 문자열 길이를 이진수로 변환

이렇게 해서 0제거한것 , 변환한것을 카운팅해서 return해주면된다.

그렇다면 이제 swift에서 이진수 변환은 어떻게 하는가?


공식문서 - 진수변환

공식문서 코드

let v = 999_999
print(String(v, radix: 2)) //"11110100001000111111"
print(String(v, radix: 16)) //Prints "f423f"
print(String(v, radix: 16, uppercase: true)) //"F423F"

엥 ? 999_999는 뭐지?

999999 라고 생각하면 된다! 우리가 999,999 << 이렇게 쉼표를 넣어주는 것처럼 언더스코어로 이를 표현할 수 있다고 한다. 숫자 가독성을 높이기 위한 하나의 표현식이다. 물론 프로그램이 동작하는데에는 전혀 영향을 주지 않는다.

사용방법

다시 돌아와서, 엄청 간단하게 String(value, radix:변환하고자하는 진수 숫자) 를 넣어주면 String으로 변환하면서 같이 수행을 해줄 것이다. 2~36진수까지 가능하다진수변환 파라미터

uppercase는 왜 있는데?

10진수 이상으로 되었을때 11을 'a'라고 표현하듯이 영문자가 포함되게 되는데, 이때 이를 대문자로 바꿔주는 속성이다. default는 false로 되어있다.


풀이

import Foundation

class Solve {
    func changeToBinary(value: inout String, cnt: inout Int) {
        let tmp = value.count
        value = String(Array(value).filter { $0 == "1" })
        cnt += tmp - value.count
        value = String(value.count, radix: 2)
    }

    func solution(_ s: String) -> [Int] {
        var str = s
        var loopCnt = 0
        var cnt = 0
        while str != "1" {
            changeToBinary(value: &str, cnt: &cnt)
            loopCnt += 1
        }
        return [loopCnt, cnt]
    }
}

let solve = Solve()
print(solve.solution("01110"))

지난 포스팅 때 공부했었던 inout 변수를 활용해서 changeToBinary함수에서 이를 사용해줬다.
strcnt를 inout 활용해서 함수안에서 값을 변경해줬다.
1이 나올때까지 반복해야하니 while문으로 str != "1" while문으로 돌아갈 때마다 loopCnt+=1해줬다.

다른 유저 풀이

 while copiedS != "1" {
        removedZero += copiedS.replacingOccurrences(of: "1", with: "").count
        copiedS = String(copiedS.replacingOccurrences(of: "0", with: "").count, radix: 2)
        count += 1
    }

replacingOccurrences ?

세상 별거가 다 있다 싶었다. 알아보니 replace하는 것인데, 공식문서의 설명은 다음과 같다.
replaceOccurrences 공식문서
replacingoccurrences

결국 내가 바꾸자하는거를 지정해주면 그것을 바꾼채로 string으로 return한다는 것이다.

코드 살펴보면..

  1. copiedS.replacingOccurrences(of: "1", with: "").count 로 1을 다지운 string, 즉 0의 개수를 더해주고
  2. String(copiedS.replacingOccurrences(of: "0", with: "").count, radix: 2) 여기에서 이제 0을지운채로 해당 길이를 이진수로 변환해주면 단 두줄로 전반적인 로직이 완성이 된다.

그럼 이거 replacingOccurrences 는 여러개 제거를 못하나 ?

  1. 체이닝 (체이닝으로 연속되게 사용해줄 수 있다.)

let musicCode = "CC#BCC#BCC#BCC#B"
let newMusicCode = musicCode.replacingOccurrences(of: "C#", with: "V")
                            .replacingOccurrences(of: "D#", with: "W")
                            .replacingOccurrences(of: "F#", with: "X")
                            .replacingOccurrences(of: "G#", with: "Y")
                            .replacingOccurrences(of: "A#", with: "Z")
// CVBCVBCVBCVB"
  1. 정규식 활용

    options 로 regularExpression을 통해서 난 정규식을 쓸거야 라고 지정해주면 of: 에 이제 정규식을 집어넣으면 된다.
let text = "[1,2,3,4,5]"
let newText = text.replacingOccurrences(of: "[\\[\\]]", with: "", options: .regularExpression)
// "1,2,3,4,5

그러면 options에는 뭐가 들어갈 수 있나?

options에는
공식문서를 보시면 options에는 NSString.CompareOptions가 들어갈 수 있다고 한다. 또한 배열로, 여러개를 옵션으로 또 지정해줄 수도 있다.

NSString.CompareOptions

  1. caseInsensitive
    대소문자를 구분하지 않음

    let result = "Hello World".replacingOccurrences(of: "hello", with: "Hi", options: .caseInsensitive)
    // 결과: "Hi World"
  2. literal
    문자열을 리터럴로 간주, 정확히 일치하는 텍스트를 대체

    let result = "Hello World".replacingOccurrences(of: "l", with: "1", options: .literal)
    // 결과: "He11o Wor1d"
  3. backwards
    문자열의 끝에서부터 검색

    let result = "Hello World".replacingOccurrences(of: "l", with: "1", options: .backwards)
    // 결과: "Hello Wor1d" (뒤에서부터 하나씩 검색 후 교체)
  4. anchored
    a. 대체할 문자열이 문자열의 시작 또는 끝에 있어야만 변경됨!

    let result = "Hello World".replacingOccurrences(of: "Hello", with: "Hi", options: .anchored)
    // 결과: "Hi World"

    b. 이럴때는 그래서 변경이 안됨 !

    let result = "Say Hello World".replacingOccurrences(of: "Hello", with: "Hi", options: .anchored)
    		print(result)
    		// 결과: "Say Hello World" (시작점이 아니므로 대체되지 않음)
  5. regularExpression
    정규식을 사용하는 옵션

    let result = "123abc".replacingOccurrences(of: "\\d+", with: "Numbers", options: .regularExpression)
    // 결과: "Numbersabc"
  6. 여러개 복합 사용
    여러 옵션을 조합 가능

    let result = "Hello World".replacingOccurrences(of: "hello", with: "Hi", options: [.caseInsensitive, .anchored])
    // 결과: "Hi World" (대소문자 무시하며 시작 부분에서만 대체)

느낀점

SWIFT는 다른분 답안을 볼 때마다 새로운 메소드가 등장하는 느낌이다.
다음엔 이거 replacingOccurrences 써봐야할 듯하다.

profile
기억보단 기록을

0개의 댓글