이번 주에도 프로그래머스를 집중적으로 팠습니다. 오랜만에 다시 시작하는 PS이니만큼 쉬운 문제들을 좀 풀면서 적응하고, JS로 풀이하는 훈련도 하려 했는데...
무려 레벨 0 100제가 새로 나왔네요.
코테나 PS에 처음 입문하거나 레벨 1도 버거운 초심자들을 위해 제작했다고 합니다.
문제 대부분의 난이도가 굉장히 쉽기 때문에 금주 풀었던 문제들 중 특히 어려웠거나 생각할 거리가 있었던 문제들을 중심으로 작성하려 합니다.
주어진 문자열을 "aya", "ye", "woo", "ma"
네 개의 문자열이 반복되지 않는 조합으로 만들 수 있는지 묻는, 문자열 구현 문제입니다. 일단 문자열 중 완벽하게 겹치는 형태가 없으니 쉽게 느껴질 수 있지만, 이런 유형의 문제가 처음이라 조금 시간이 걸렸습니다. ⏱️
풀이는 이렇게 했습니다:
function solution(babbling) {
let result = 0;
for (let word of babbling) {
if (word.replace(/(aya)|(ye)|(woo)|(ma)/g, '') == '' &&
!word.match(/(ayaaya)|(yeye)|(woowoo)|(mama)/g)) {
result++;
}
}
return result;
}
정규표현식의 반복 패턴 변경자를 이용한 풀이입니다. regexp 짱!
난이도 측면에서든, 개념 측면에서든 여기서 다루는 문제 중에서 가장 쉬웠지만, 한 번은 짚고 넘어갈 필요가 있다고 생각한 문제였습니다.
단순히 주어진 자연수가 어떤 자연수의 제곱수면 1을, 아니면 2를 return하는 문제였습니다. 처음에는 단순히 지수 연산자를 이용해서 풀었는데,
function solution(n) {
return ((n ** 0.5) ** 2 == n) ? 1 : 2
}
여기서 치명적인 실수는, (n ** 0.5) ** 2
는 결국 n
과 같기에 제곱수를 판별하는데 의미가 없는 식이었습니다. 사소한 구현상의 실수였지만, 실수 단위에서 문제를 다룰 때는 더욱 신중할 필요가 있다는 교훈을 주었습니다.
올바른 풀이:
function solution(n) { return (Math.floor(n ** 0.5) ** 2 == n) ? 1 : 2 }
앞의 '옹알이' 문제와 맥락은 같지만, 저의 풀이 방식은 상당히 상이했던 문제였습니다. 영어로 나타낸 숫자가 붙어 있는 배열을 아라비아 숫자로 변화하는 문제로, 마찬가지로 영어 숫자 사이에는 겹치는 부분이 없기 때문에 각 자리 사이 연관성은 없습니다.
ston = { // means string to number
'one': 1,
'two': 2,
...
}
function solution(numbers) {
let result = '';
Loop: while (true) {
for (let i in ston) {
if (numbers.startsWith(i)) {
result += ('' + ston[i]);
numbers = numbers.slice(i.length);
}
if (!numbers) {
break Loop;
}
}
}
return +result;
}
사실, 다시 보니 while (numbers)
로 바꾸면 굳이 break
문을 넣어줄 필요는 없었네요 😅 일단 맞고 보자는 생각이었던 거 같습니다;
웬지 이 음악과 함께 풀어야 할 것 같은 문제네요. ➡️ 🧷📻
네 점의 좌표가 주어질 때, 이들을 각각 이은 두 쌍의 직선이 평행한 경우가 있는지 판별하는 문제입니다.
function isParallel(A1, A2, B1, B2) {
return ((A1[0] == A2[0] && B1[0] == B2[0]) ||
((A2[1] - A1[1]) / (A2[0] - A1[0]) == (B2[1] - B1[1]) / (B2[0] - B1[0])))
}
function solution(dots) {
return +(
isParallel(dots[0], dots[1], dots[2], dots[3]) ||
isParallel(dots[0], dots[2], dots[1], dots[3]) ||
isParallel(dots[0], dots[3], dots[1], dots[2])
)
}
이 풀이에서 함수 isParallel
은 두 직선 , 이 평행한지 판별하는 함수인데, 여기서 주의하며 구현했던 점은 선분이 x축과 수직일 때입니다. x의 증분이 0이 되면 Division by zero
가 되니, x좌표가 서로 같은지에 대한 조건을 따로 달았습니다.
Javascript는 0으로 나누면 Infinity를 뱉으니 상관없지 않나요? 🤔
음... 그건 JS가 이상한 거니까 😑
과거 2학년 꼬꼬마 시절 때 풀지 못했던 문제입니다. 1년 뒤 다시 풀어 보니 느낌이 새롭네요.
제작년 카카오 인턴쉽에서 출제된 문제인데,
각 숫자 자판을 정해진 로직에 맞춰 입력하는 손가락을 맞추는 문제입니다.
positions = {
1: [0, 0], 2: [0, 1], 3: [0, 2],
4: [1, 0], 5: [1, 1], 6: [1, 2],
7: [2, 0], 8: [2, 1], 9: [2, 2],
0: [3, 1]
};
function compareDistance(l, r, t) {
let leftDistance = Math.abs(l[0] - t[0]) + Math.abs(l[1] - t[1]);
let rightDistance = Math.abs(r[0] - t[0]) + Math.abs(r[1] - t[1]);
return (leftDistance < rightDistance ? 'left' : (
leftDistance > rightDistance ? 'right': 'same'
));
}
function solution(numbers, hand) {
let answer = '';
let left = [3, 0]; let right = [3, 2]; // 각 손의 위치
for (let digit of numbers) {
if ([1, 4, 7].includes(digit)) {
answer += 'L';
left = positions[digit];
} else if ([3, 6, 9].includes(digit)) {
answer += 'R';
right = positions[digit];
} else {
let compareDistanceResult = compareDistance(left, right, positions[digit]);
if (compareDistanceResult == 'left') {
answer += 'L';
left = positions[digit];
} else if (compareDistanceResult == 'right') {
answer += 'R';
right = positions[digit];
} else {
if (hand == 'left') {
answer += 'L'; left = positions[digit]
} else {
answer += 'R'; right = positions[digit]
}
}
}
}
return answer;
}
정말 크고 아름다운 코드네요. 어디서부터 설명을 적어야 할지 모르겠습니다.
풀이를 찾아보니 /[147]/.test(digit)
이렇게 regexp를 이용해서 자릿수를 거르는 방법도 있더군요. 배울 점이 많았던 문제였던 것 같습니다.
영어 끝말잇기를 진행하다가 처음으로 틀린 사람의 번호와 순서를 계산하는 문제입니다. 개념에 비해 구현 난이도만 높아서 그런지 레벨 1에 있어도 될 것 같은 문제였죠.
function solution(n, words) {
let lastLetter = '';
let wordList = [];
let turn = 0;
let isProblem = false;
Loop: for (let word of words) {
turn++;
if (!word.startsWith(lastLetter) ||
wordList.includes(word)) {
isProblem = true;
break Loop;
}
lastLetter = word.at(-1);
wordList.push(word);
}
if (isProblem) {
return [turn%n == 0 ? n : turn%n, Math.ceil(turn/n)]
} else {
return [0, 0];
}
}
예전에 자주 풀었던 피보나치 수열 유형의 dp 문제였습니다. 이건 문제자체보다는 풀이 때문에 기억에 남는 문제인데,
function solution(n) {
let fib = [1, 2];
for (let i=2; i<=2000; i++) {
fib.push((fib.at(-1) + fib.at(-2)) % 1234567);
}
return fib[n-1]
}
이렇게 dp로 구현할 문제를 제한 범위 내의 fib 배열을 통째로 집어넣은 광인을 만났습니다... 여기서 볼 수 있습니다.
여러 가지 한글 Esolang들을 접하면서, 저도 이런 언어를 하나쯤 만들고 싶어졌습니다. 처음 생각했던 건 아임뚜렛 밈에서 파생한 아잇...어
였지만, 인기가 다 식어서 보류하기로 했습니다.
뭉'랭'이도 고려해보았지만, 이미 있는 언어더군요. 그래서 어쩔 수 없이 아잇!어
를 만들어보기로 했습니다. 제 손으로 구현체까지 직접 만들어서요.
PS 문제를 하나 풀려 했는데, 아희 자제로 알고리즘을 짜는 게 쉽지가 않더군요.
방방다망함
한 줄 던지고 말겠습니다. print(sum(map(int, input().split())))
와 동치입니다.