문제 설명
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함수에서 이를 사용해줬다.
str
과cnt
를 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 }
세상 별거가 다 있다 싶었다. 알아보니 replace하는 것인데, 공식문서의 설명은 다음과 같다.
replaceOccurrences 공식문서
결국 내가 바꾸자하는거를 지정해주면 그것을 바꾼채로 string으로 return한다는 것이다.
코드 살펴보면..
copiedS.replacingOccurrences(of: "1", with: "").count
로 1을 다지운 string, 즉 0의 개수를 더해주고String(copiedS.replacingOccurrences(of: "0", with: "").count, radix: 2)
여기에서 이제 0을지운채로 해당 길이를 이진수로 변환해주면 단 두줄로 전반적인 로직이 완성이 된다. 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"
options
로 regularExpression을 통해서 난 정규식을 쓸거야 라고 지정해주면 of: 에 이제 정규식을 집어넣으면 된다. let text = "[1,2,3,4,5]"
let newText = text.replacingOccurrences(of: "[\\[\\]]", with: "", options: .regularExpression)
// "1,2,3,4,5
공식문서를 보시면 options에는 NSString.CompareOptions가 들어갈 수 있다고 한다. 또한 배열로, 여러개를 옵션으로 또 지정해줄 수도 있다.
caseInsensitive
대소문자를 구분하지 않음
let result = "Hello World".replacingOccurrences(of: "hello", with: "Hi", options: .caseInsensitive)
// 결과: "Hi World"
literal
문자열을 리터럴로 간주, 정확히 일치하는 텍스트를 대체
let result = "Hello World".replacingOccurrences(of: "l", with: "1", options: .literal)
// 결과: "He11o Wor1d"
backwards
문자열의 끝에서부터 검색
let result = "Hello World".replacingOccurrences(of: "l", with: "1", options: .backwards)
// 결과: "Hello Wor1d" (뒤에서부터 하나씩 검색 후 교체)
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" (시작점이 아니므로 대체되지 않음)
regularExpression
정규식을 사용하는 옵션
let result = "123abc".replacingOccurrences(of: "\\d+", with: "Numbers", options: .regularExpression)
// 결과: "Numbersabc"
여러개 복합 사용
여러 옵션을 조합 가능
let result = "Hello World".replacingOccurrences(of: "hello", with: "Hi", options: [.caseInsensitive, .anchored])
// 결과: "Hi World" (대소문자 무시하며 시작 부분에서만 대체)
SWIFT는 다른분 답안을 볼 때마다 새로운 메소드가 등장하는 느낌이다.
다음엔 이거 replacingOccurrences
써봐야할 듯하다.