출처: 프로그래머스 코딩 테스트 연습, 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
** 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은 아스키코드를 문자열로 변환해주는 것 같다.
'프로그래머스 > level 1' 카테고리의 다른 글
[프로그래머스] 콜라츠 추측 (0) | 2021.08.03 |
---|---|
[프로그래머스] 최대공약수와 최소공배수 (0) | 2021.08.03 |
[프로그래머스] 평균 구하기 (0) | 2021.07.23 |
[프로그래머스] 하샤드 수 (0) | 2021.07.23 |
[프로그래머스] 핸드폰 번호 가리기 (0) | 2021.07.23 |