let sum = null; let cycle = 0; let sumStr = N.toString();
입력받은 수와 비교할 새로운 수인 sum, 사이클 수, 자릿수 연산을 위해 사용할 sum의 문자열 변수를 선언합니다. 이 때 sum은 null로 초기화하였는데 이는 초기값과 입력값이 겹쳐 for문이 실행되지 않는 것을 방지하기 위해 null로 선언하였습니다. 만약 0으로 초기화한다면 입력값이 0일 때 for문이 수행되지 않습니다. 첫 for문에서 검사할 N의 자릿수를 계산하기 위해 sum 문자열 변수의 초기값은 N의 문자열 형태입니다.
for(;sum!=N;cycle++)
사이클로 만들어진 새로운 수가 입력받은 수와 같아질 때까지 반복합니다. 한 사이클이 끝날 때마다 사이클 값은 증가됩니다.
즉 입력값은 2 1 2 3 4이지만 실제로 처리된 입력값은 2 2 4 가 되서 입력값을 제대로 받아오지 못하는 경우가 생깁니다. 이를 방지하기 위해 다음과 같은 처리방법을 순서대로 시도했습니다.
1. 구분자를 \r\n으로 구분
공백이 아닌 \r\n을 이용해 구분하면 될 것 같아서 시도해보았습니다만 다음과 같은 문제가 발생했습니다.
-> 여러 줄 표준스트림 : 2
1 2
3 4
버퍼 : 0 : 0x32
1 : 0x0D
2 : 0x0A
3 : 0x31
4 : 0x20
5 : 0x32
6 : 0x0D
7 : 0x0A
8 : 0x33
9 : 0x20
10 : 0x34
11 : 0x0D
12 : 0x0A
toString() -> "2\r\n1 2\r\n3 4\r\n"
split("\r\n") -> 0 : "2"
1 : "1 2"
2 : "3 4"
3 : ""
놀랍게도 배열 끝에 ""(빈 문자열)이 새롭게 추가되는 것을 보았습니다. 이유를 알아내기 위해 몇 번의 테스트를 거친 결과 javascript의 split 메소드가 문자열이 구분자로 끝날 경우 반환할 배열 끝에 빈 문자열을 추가하는 기능을 가지고 있다고 추측하였습니다. 그래서 이를 해결하기 위해 다음의 2번 방법을 시도하였습니다.
2. split을 쓰기 전에 문자열 끝의 구분자를 제거.
구분자를 "\r\n" 으로 사용해야하니 문자열 끝의 \r\n 부분을 제거해주면 될 것 같았습니다. javascript에서는 문자열 끝에 있는 공백 및 CR, LF 등을 제거해주는 trimEnd() 메소드를 제공해주니 이 메소드를 사용하면 될 것 같습니다. 실제로 문자열 끝의 제어문자들이 사라진 것을 확인할 수 있었습니다.
-> 여러 줄 표준스트림 : 2
1 2
3 4
버퍼 : 0 : 0x32
1 : 0x0D
2 : 0x0A
3 : 0x31
4 : 0x20
5 : 0x32
6 : 0x0D
7 : 0x0A
8 : 0x33
9 : 0x20
10 : 0x34
11 : 0x0D
12 : 0x0A
toString() -> "2\r\n1 2\r\n3 4\r\n"
trimEmd() -> "2\r\n1 2\r\n3 4"
split("\r\n") -> 0 : "2"
1 : "1 2"
2 : "3 4"
하지만 왜인지 이방법또한 제대로 실행되지 못했습니다. 그래서 계속 찾아보다가 다음과 같은 3번 해결책을 찾았습니다.
3. split을 쓰기 전에 문자열 끝의 구분자를 제거한 후 구분자를 \n으로 구분.
\r과 \n에 대해 알아보는 도중 Windows는 \r\n, Linux는 \n을 개행으로 사용한다는 정보를 얻었습니다. 백준 온라인에서 테스트하는 node.js는 웹서버에서 동작하고 웹 서버는 Linux일 확률이 높으니 표준 입력 스트림이 \r\n이 아닌 \n을 사용할 가능성이 높아보였습니다. 즉 실제로는 다음과 같이 동작할 확률이 높았습니다.
-> 여러 줄 표준스트림 : 2
1 2
3 4
버퍼 : 0 : 0x32
1 : 0x0A
2 : 0x31
3 : 0x20
4 : 0x32
5 : 0x0A
6 : 0x33
7 : 0x20
8 : 0x34
9 : 0x0A
toString() -> "2\n1 2\n3 4\n"
trimEmd() -> "2\n1 2\n3 4"
split("\n") -> 0 : "2"
1 : "1 2"
2 : "3 4"
이렇게 짜니 실제로 코드가 잘 처리되었습니다. 이제 다음 코드를 살펴봅시다.
let [T, ...inputArr] = stdinline;
줄별로 인자가 들어있는 배열을 변수 T와 inputArr에 저장합니다. 이 때 T는 stdinline[0], inputArr은 stdinline의 나머지 요소가 저장됩니다.
-> stdinline = ["2", "1 2", "3 4"]
T = "2"
inputArr = ["1 2", "3 4"]
for(let i in inputArr) { let [A, B] = inputArr[i].split(" ").map(input => { return parseInt(input);}); console.log(A+B); }
inputArr 배열의 각 요소는 "A B" 형태의 문자열을 각각 담고 있습니다. 그래서 공백을 기준으로 문자열을 분리한다음 정수로 변환하여 A과 B에 저장하였습니다. for문은 T를 사용해 돌려도 되지만 in을 사용하면 더 간편할 거 같아서 in을 사용했습니다. (T를 사용하지 않았으니 메모리 낭비이긴 합니다.) 처리 과정은 다음과 같습니다.
윤년이면 1, 아니면 0을 출력하는 코드입니다. 일단 윤년은 400의 배수이면 무조건 윤년입니다. 그런데 400의 배수는 아니지만 4의 배수인 동시에 100의 배수가 아니면 윤년입니다. 그 외의 연도는 윤년이 아닙니다. 이것을 if문으로 짜면 위와 같은 코드가 나옵니다.