안녕하세요, 최근 알고리즘 풀이 포스팅을 많이 올리는데, 책 읽으면서 공부하다가 막상 문제 풀이를 위해 코딩을 조금씩이라도 하면서 생각 하니까 시간은 좀 더 걸리고 어렵더라도 재미는 더 있는 것 같아요. 균형을 맞추는 게 중요한데.. 오늘의 알고리즘 포스팅은 이거 하나로 만족해야 할 것 같습니다.
https://acmicpc.net/problem/1110
문제
0보다 크거나 같고, 99보다 작거나 같은 정수가 주어질 때 다음과 같은 연산을 할 수 있다. 먼저 주어진 수가 10보다 작다면 앞에 0을 붙여 두 자리 수로 만들고, 각 자리의 숫자를 더한다. 그 다음, 주어진 수의 가장 오른쪽 자리 수와 앞에서 구한 합의 가장 오른쪽 자리 수를 이어 붙이면 새로운 수를 만들 수 있다. 다음 예를 보자.
26부터 시작한다. 2+6 = 8이다. 새로운 수는 68이다. 6+8 = 14이다. 새로운 수는 84이다. 8+4 = 12이다. 새로운 수는 42이다. 4+2 = 6이다. 새로운 수는 26이다.
위의 예는 4번만에 원래 수로 돌아올 수 있다. 따라서 26의 사이클의 길이는 4이다.
N이 주어졌을 때, N의 사이클의 길이를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N이 주어진다. N은 0보다 크거나 같고, 99보다 작거나 같은 정수이다.
출력
첫째 줄에 N의 사이클 길이를 출력한다.
예제 입력 1 복사
26
예제 출력 1 복사
4
예제 입력 2 복사
55
예제 출력 2 복사
3
예제 입력 3 복사
1
예제 출력 3 복사
60
예제 입력 4 복사
0
예제 출력 4 복사
1
예제 입력 5 복사
71
예제 출력 5 복사
12
문제풀이
사실 저는 이 문제를 풀면서 편법(?) 아닌 편법을 썼습니다. 뭐랄까, 출제자의 의도에 완벽하게는 맞지 않은..? 왜냐하면 이 문제는 백준 온라인 저지의 반복문 카테고리 안에 있는 문제 중 하나인데, 저는 흔히 생각할 수 있는 반복문 종류 (for, while, do-while) 대신에 재귀함수를 사용해서 풀었기 때문입니다. 그 이유는 간단한데 루프를 써서 어떻게 풀어야 할 지 잘 생각이 안났기 때문이죠 ✌🏻 하지만 따지고 보면 재귀함수 역시 자기 자신을 반복해서 호출하는 형태이기 때문에 완전히 틀렸다고도 할 수 없지 않을까요..?
그럼 코드를 보기에 앞서 제가 이 문제를 풀기 전에 염두해 뒀던 점들을 나열해 보겠습니다.
- 0보다 크고 99보다 작은 입력이 주어짐. 다음 생성되는 숫자는 덧셈 연산의 오른쪽 숫자와 결과값 숫자의 결합 (덧셈x)
- 명심해야 할 점은 덧셈 연산 결과값이 2자리일 경우 맨 오른쪽 숫자만 사용
- 초기 입력값이 1자리일 경우 앞에 '0' 을 붙여줌, e.g., 3 => 03, 7 => 07
사실 염두했던 점들이라기 보단 문제 텍스트가 길어서 제가 띄엄띄엄 읽었더니 실수를 해버렸습니다. 알고리즘 문제 풀 때는 항상 문제를 꼼꼼하게 읽는 습관을 들여야겠습니다..!
그럼 제가 작성한 코드를 살펴보겠습니다.
const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : `${__dirname}/input.txt`;
let input = fs.readFileSync(filePath).toString().trim();
if (Number(input) < 10) {
input = `0${input}`;
}
let cycle = 0;
function incrementCycle(firstDigit, secondDigit) {
let newDigit = String(Number(firstDigit) + Number(secondDigit));
if(newDigit.length > 1) {
newDigit = Number(newDigit[newDigit.length - 1]);
}
cycle++;
if (input === `${secondDigit}${newDigit}`) {
return cycle;
}
return incrementCycle(secondDigit, newDigit);
}
console.log(incrementCycle(input.split('')[0], input.split('')[1]));
먼저 input 변수에 입력값을 받고 만약 입력값이 10보다 작을 경우 앞에 0을 붙여준다는 코드입니다.
if (input.length > 1) input = `0${input}`;
이렇게도 가능하겠네요, 왜냐하면 입력값이 문자열로서 전달되기 때문입니다.
그 아래 재귀함수인 incrementCycle 함수를 보시면, 새로운 숫자 (덧셈 연산 결과값) 을 구해주고, 문자열로 변경을 해줍니다. 혹시 결과값이 2자리일 경우 오른쪽 숫자만 따로 사용하기 위함이죠. 그 후에 한 싸이클 돌았기 때문에 cycle 변수에 1을 더해주고 처음 입력값과 새로 합성된 숫자가 같은지 비교해 줍니다. 만약 그렇다면 싸이클 변수를 리턴 해주고, 그렇지 않다면 다시 incrementCycle 함수를 호출해서 똑같은 과정을 반복합니다.
제가 이 문제를 재귀 함수로 푼 이유는 위에서도 언급했다시피 일반 반복문을 사용하면 어떻게 해야할 지 감이 잘 안잡히기도 했고 (지저분한 코드..), 재귀함수를 연습하기 위함도 있었습니다. 아직 재귀함수가 마냥 편하지는 않지만, 계속 연습하다보면 좋은 결과가 있지 않을까 싶네요.
그럼 이번 포스트는 이 정도로 마무리 짓도록 하겠습니다. 다들 즐거운 하루 보내세요~
'Studying > Algorithms' 카테고리의 다른 글
[알고리즘 떠먹여 주는 남자] 백준 2798 - 블랙잭 for Node.js (0) | 2022.04.05 |
---|---|
[알고리즘 떠먹여 주는 남자 - 번외편] 백준 알고리즘 풀이용 로컬 테스트 환경 구축 (0) | 2022.04.05 |
[알고리즘 떠먹여 주는 남자] 백준 15552 - 빠른 A + B for Node.js (0) | 2022.04.04 |
[알고리즘 떠먹여 주는 남자] 백준 8393 - 합 for Node.js (0) | 2022.04.04 |
[알고리즘 떠먹여 주는 남자] 백준 1157 - 단어 공부 for Node.js (0) | 2022.04.04 |