본문 바로가기
Xcode/Swift - Algorithm

Swift) 프로그래머스(Lv1) 시저 암호 (String)

by 후르륵짭짭 2020. 7. 14.
728x90
반응형

programmers.co.kr/learn/courses/30/lessons/12926

 

코딩테스트 연습 - 시저 암호

어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 AB는 1만큼 밀면 BC가 되고, 3만큼 밀면 DE가 됩니다. z는 1만큼 밀면 a가

programmers.co.kr

안녕하세요 후르륵짭짭 입니다

이번에는 시저 암호라는 문제를 풀어 봤는데요.

C++이나 JAVA에 비해 Swift의 약점인 String 문자 변경에 대해서 다뤄 볼려고 합니다!

처음에는 이렇게 풀었습니다.

func solution(_ s:String, _ n:Int) -> String {
    
    var answer : String = ""
    let z = UInt8( UnicodeScalar("z").value )
    let Z = UInt8( UnicodeScalar("Z").value )
    
    let convertList =  s.map { (char) -> String in
        
        var temp : String = String(char)
        
        if ("a"..."z").contains(char){
            
            let number = char.asciiValue! + UInt8(n)
            
            if number > z {
                temp = String(UnicodeScalar( 96 + UInt8(number - z) ))
            }
            else{
                temp = String(UnicodeScalar( char.asciiValue! + UInt8(n) ))
            }
            
            
        }
        else if ("A"..."Z").contains(char){
            
            let number  = char.asciiValue! + UInt8(n)
            
            if number > Z {
                temp = String(UnicodeScalar( 64 + UInt8(number - Z) ))
            }
            else {
                temp = String(UnicodeScalar( char.asciiValue! + UInt8(n) ))
            }
            
        }
        
        return temp
    }
    
    for item in convertList{
            answer += item
    }
    
    
    return answer
}

그럼 하나 씩 알아보도록 하겠습니다.

** 문자열을 아스키코드로 변경하기 **

Swift에서는 문자열 하나를 아스크코드로 변경 할 수가 없습니다. 

따라서 UnicodeScalar("문자열").value로 해줘야 합니다.

let Z = UInt8( UnicodeScalar("Z").value )

그래서 아스키코드 번호가 나옵니다.

아니면 변수에 문자 하나를 담고 그 문자에서 asciiValue 를 해줘야합니다.

그리고 계산을 하려면 UInt8 형태로 해줘야합니다.

let number = char.asciiValue! + UInt8(n)

 

** 문제 해결 **

z => 122

Z => 90

이렇게 됩니다.

만약에 "B" + 25를 하게 된다면 66 + 25 = 91 이 됩니다.

엄청나게 오버 하게 되죠 ㅎㅎㅎ

그래서 91 - 90 을 빼주면 1 이 남게 됩니다.

즉, Z에서 한 칸 더 움직인거다. 라는 의미가 되기 때문에 64에서 뺀수를 더해주는 겁니다.

 

** 더 좋은 방법 **

풀면서 먼가 만족 스럽지 않았습니다.

그래서 다른 사람의 코드를 봤습니다.

func solution2(_ s:String, _ n:Int) -> String {
    
    let answer = s.utf8.map { (codeUInt) -> String in
        
        var number = Int(codeUInt)
        
        if (65...90).contains(number){
            
            number = (number + n - 65 ) % 26 + 65
            
        }
        else if (97...122).contains(number){
            
            number = (number + n - 97 ) % 26 + 97
        }
        
        return String(UnicodeScalar(number)!)
    }
    
    return answer.joined()
    
}

이렇게 문제를 해결 한 것인데,

일단 문자열을 utf8 형태로 변경 해주고 거기서 고차함수 map을 해줍니다.

그런 다음 number 가 소문자에 해당하는지 대문자에 해당하는지 구별 해줍니다.

그런 다음 결국 위의 저의 해결 방법과 같아 집니다.

만약 "B" + 25 를 해서 91 이 되고 거기서 65를 빼준다는 의미는 "A"에서 "B"가 얼마나 떨어져 있냐를 확인 해 줍니다.

따라서 "A"에서 몇칸 앞에 있는가를 찾을 수 있져

그럼 26칸 이동한 것이 확인이 되고 여기서 26을 나눠주면 0 + 65 를 해주면

즉 A가 나오게 됩니다.

 

이 풀이를 보고 새롭게 알게 된 것은

문자열을 utf8으로 변경해서 아스키코드로 모두 한번에 변경이 되는 것을 알게 되었고

문자열 배열로 된 것을 String으로 한번에 묶어 주기 위해서는 joined()를 써주면 된다는 것도

처음 알았습니다.

728x90
반응형

댓글