프로그래머스/level 1

[프로그래머스] 시저 암호

binaryJournalist 2021. 7. 27. 18:47
반응형

 

출처: 프로그래머스 코딩 테스트 연습, https://programmers.co.kr/learn/challenges

 

 

 

 

 

 

** Javascript

 

 

문제를 보고 ASCII CODE로 shift 해야 한다는 걸 직감했다

 

그래서 구글링 해봤더니 Caeser Cipher 라는 게 있었다. 이게 문제 제목에서 가리킨 시저 암호였다.

 

 

처음 소스는 이랬다. (하지만 제출은 안 했다. 갓택오버플로우 베낀 소스여서)

 

1)

function solution(s, k) {
    var n = 26; // alphabet letters amount
    if (k < 0) {
        return caesarCipher(s, k + n);
    }
    return s.split('')
        .map((c) => {
            if (c.match(/[a-z]/i)) {
                const code = c.charCodeAt();
                const shift = code >= 65 && code <= 90 ? 65 : code >= 97 && code <= 122 ? 97 : 0;
                return String.fromCharCode(((code - shift + k) % n) + shift);
            }
            return c;
        }).join('');
}

 

 

정리하여 제출한 소스는 다음과 같다. 하지만 너무나 마음에 안듦

 

 

2)

 

function solution(s, n) {
    const alphabet = 26;
    const answer = s.split("").reduce((acc, curr) => {
        const asciiCode = curr.charCodeAt();
        if (asciiCode === 31 || asciiCode === 32) return acc + curr;
        const shift = (asciiCode >= 65 && asciiCode <= 90) ? 65
            : (asciiCode >= 97 && asciiCode <= 122) ? 97 : 0; 
        return acc + String.fromCharCode((asciiCode - shift + n) % alphabet + shift);
    }, "");
    return answer;
}

 

 

 

추천을 많이 받은 풀이 중 가장 깔끔한 것은 아래 풀이다.

아스키 코드 변환 함수를 사용하지 않고도 풀 수 있었다.

 

function solution(s, n) {
    var upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var lower = "abcdefghijklmnopqrstuvwxyz";
    var answer= '';

    for(var i =0; i <s.length; i++){
        var text = s[i];
        if(text == ' ') {
            answer += ' '; 
            continue;
        }
        var textArr = upper.includes(text) ? upper : lower;
        var index = textArr.indexOf(text)+n;
        if(index >= textArr.length) index -= textArr.length;
        answer += textArr[index];
    }
    return answer;
}

 

 

3)

위 풀이를 참고하여 다시 작성한 풀이는 아래와 같다.

 

function solution(s, n) {
    const lower = "abcdefghijklmnopqrstuvwxyz";
    const upper = lower.toUpperCase();
    
    return Array.from(s).reduce((acc, curr) => {
        if(curr === " ") return acc += curr;
        if(lower.indexOf(curr) > -1) acc += lower[(lower.indexOf(curr) + n) % 26];
        if(upper.indexOf(curr) > -1) acc += upper[(upper.indexOf(curr) + n) % 26];
        return acc;
    }, "");
}

 

 

 

 

** Java

 

 

java에서는 아스키코드를 이용하지 않고 풀어봤다.

 

class Solution {
    public String solution(String s, int n) {
        String lowerCases = "abcdefghijklmnopqrstuvwxyz";
        String upperCases = lowerCases.toUpperCase();
        String[] strArr = s.split("");
        StringBuilder sb = new StringBuilder();
        for (String str : strArr) {
            if (str.equals(" ")) {
                sb.append(str);
                continue;
            }
            if (lowerCases.indexOf(str) > -1) {
                sb.append(lowerCases.charAt((lowerCases.indexOf(str) + n) % 26));
            }
            if (upperCases.indexOf(str) > -1) {
                sb.append(upperCases.charAt((upperCases.indexOf(str) + n) % 26));
            }
        }
        return sb.toString();
    }
}

 

String에서 [인덱스] 로 가져오질 못해서 .charAt(인덱스)을 사용하였다.

그리고 문자열 가공을 편하게 하기 위해 처음부터 StringBuilder를 이용하였다.

 

 

 

추천 풀이를 보면

 

class Caesar {
    String caesar(String s, int n) {
        String result = "";
    n = n % 26;
    for (int i = 0; i < s.length(); i++) {
      char ch = s.charAt(i);
      if (Character.isLowerCase(ch)) {
        ch = (char) ((ch - 'a' + n) % 26 + 'a');
      } else if (Character.isUpperCase(ch)) {
        ch = (char) ((ch - 'A' + n) % 26 + 'A');
      }
      result += ch;
    }
        return result;
    }

    public static void main(String[] args) {
        Caesar c = new Caesar();
        System.out.println("s는 'a B z', n은 4인 경우: " + c.caesar("a B z", 4));
    }
}

 

여기서 ch - 'a' 와 ch - 'A' 가 있는데 위 자바스크립트 풀이에서 shift 값을 소문자, 대문자 여부를 따져 65, 97 값을 만들어주는 것과 같은 방법인 것 같다.

java에서는 따로 ascii 코드 변환 함수를 쓰지 않고 char끼리 바로 덧셈, 뺄셈으로 구하는 것 같다.

ascii 코드 -> char는 char 캐스팅으로 끝내고 말이다.

 

 

 

 

다른 풀이의 경우 생경한 메소드를 사용했다.

 

class Caesar {
    public String caesar(String s, int _n) {
        return s.chars().map(c -> {
            int n = _n % 26;
            if (c >= 'a' && c <= 'z') {
                return 'a' + (c - 'a' + n) % 26;
            } else if (c >= 'A' && c <= 'Z') {
                return 'A' + (c - 'A' + n) % 26;
            } else {
                return c;
            }
        }).mapToObj(c -> String.valueOf((char)c))
        .reduce((a, b) -> a + b).orElse("");
    }

    public static void main(String[] args) {
        Caesar c = new Caesar();
        System.out.println("s는 'a B z', n은 4인 경우: " + c.caesar("a B z", 4));
    }
}

 

String -> char -> int -> char -> String 되고 있다. 이를 위해 mapToObj 를 함께 사용하였다.

 

mapToObj 말고도 mapToDouble, mapToLong, mapToInt 등이 있다.

 

 

 

 

위 예시를 보면 mapToObj에 대해 더 쉽게 알 수 있다.

출처: https://dev-kani.tistory.com/32

 

[Stream API] 중간 연산 - map 메서드

개념 스트림은 파라미터로 제공되는 함수( Function 관련된 함수형 인터페이스)를 적용해서 기존 요소를 새로운 요소로 매핑시키는 map 이라는 메서드를 제공한다. 기존 값을 변경한다는 개념보다

dev-kani.tistory.com

 

 

 

 

 

 

** Python

 

 

 

python 도 거의 같은 식으로 풀었다.

 

lower = 'abcdefghijklmnopqrstuvwxyz'
upper = lower.upper()

def solution(s, n):
    answer = ''
    for i in list(s):
        if lower.find(i) > -1:
            answer += lower[(lower.find(i) + n) % 26]
        elif upper.find(i) > -1:
            answer += upper[(upper.find(i) + n) % 26]
        else:
            answer += i
    return answer

 

 

추천을 많이 받은 풀이 중 ascii 코드를 이용한 풀이는 아래와 같다.

 

# 문제가 개편되었습니다. 이로 인해 함수 구성이나 테스트케이스가 변경되어, 과거의 코드는 동작하지 않을 수 있습니다.
# 새로운 함수 구성을 적용하려면 [코드 초기화] 버튼을 누르세요. 단, [코드 초기화] 버튼을 누르면 작성 중인 코드는 사라집니다.
def caesar(s, n):
    s = list(s)
    for i in range(len(s)):
        if s[i].isupper():
            s[i]=chr((ord(s[i])-ord('A')+ n)%26+ord('A'))
        elif s[i].islower():
            s[i]=chr((ord(s[i])-ord('a')+ n)%26+ord('a'))

    return "".join(s)
    # 주어진 문장을 암호화하여 반환하세요.


# 실행을 위한 테스트코드입니다.
print('s는 "a B z", n은 4인 경우: ' + caesar("a B z", 4))

 

 

python 내장함수를 잘 모르는데 isupper() 와 islower()를 이용했다면 더 쉬웠을 것 같긴 하다.

 

그리고 내장함수 중 ord 는 문자열을 아스키코드화 시켜주는 것이고 chr은 아스키코드를 문자열로 변환해주는 것 같다.

반응형