[카테고리]
코딩테스트 연습 > 2025 프로그래머스 코드챌린지 2차 예선 > 택배 상자 꺼내기
[문제설명]
1 ~ n의 번호가 있는 택배 상자가 창고에 있습니다. 당신은 택배 상자들을 다음과 같이 정리했습니다.
왼쪽에서 오른쪽으로 가면서 1번 상자부터 번호 순서대로 택배 상자를 한 개씩 놓습니다. 가로로 택배 상자를 w개 놓았다면 이번에는 오른쪽에서 왼쪽으로 가면서 그 위층에 택배 상자를 한 개씩 놓습니다. 그 층에 상자를 w개 놓아 가장 왼쪽으로 돌아왔다면 또다시 왼쪽에서 오른쪽으로 가면서 그 위층에 상자를 놓습니다. 이러한 방식으로 n개의 택배 상자를 모두 놓을 때까지 한 층에 w개씩 상자를 쌓습니다.
( ... 이하 생략 )
자세한 문제설명은 아래 링크 참고
https://school.programmers.co.kr/learn/courses/30/lessons/389478
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
[문제풀이]
function solution(n, w, num) {
var answer = 0;
let lastRow = Math.ceil(n/w);
let lastCol = n%w === 0 ? w : n%w;
let lastLCol = lastRow%2 === 1 ? lastCol : (w+1)-lastCol;
for(let numRow=0; numRow<lastRow; numRow++) {
if(((numRow)*w)+1<=num && num<=(numRow+1)*w) {
let numCol = num%w === 0 ? w : num%w;
let numLCol = numRow%2 === 0 ? numCol : (w+1)-numCol;
answer = lastRow - numRow;
if(lastRow%2 === 1 && lastLCol < numLCol) answer -= 1;
if(lastRow%2 === 0 && lastLCol > numLCol) answer -= 1;
break;
}
}
return answer;
}
<변수 설명>
| n | 마지막 상자 번호 |
| w | 최대 행의 수 (가로로 깔 수 있는 최대 상자의 수) |
| num | 꺼내야하는 상자 번호 |
| answer | 최종 제출 답 (num을 꺼내기위해 필요한 상자의 개수) |
| lastRow | 마지막 상자가 위치한 행 (총 상자탑의 층수) |
| lastCol | (해당 줄 시작지점기준으로) 마지막 상자가 위치한 열 |
| lastLCol | (왼쪽기준으로) 마지막 상자가 위치한 열 |
| numRow | 꺼내야하는 상자가 위치한 행 |
| numCol | (해당 줄 시작지점기준으로) 꺼내야하는 상자가 위치한 열 |
| numLCol | (왼쪽기준으로) 꺼내야하는 상자가 위치한 열 |
이렇게 말로 설명을 하면 이해가 안가니.. 그림으로 설명하면 아래와 같다.

<코드설명>
일단 코드의 대략적인 흐름은 아래 순서에 맞춰 작성해나갔다.
① 마지막 상자가 있는 위치 구하기
let lastRow = Math.ceil(n/w);
let lastCol = n%w === 0 ? w : n%w;
let lastLCol = lastRow%2 === 1 ? lastCol : (w+1)-lastCol;
- 상자의 행 위치 (lastRow)
- Math.ceil 자바스크립트 함수를 이용하여 마지막 상자의 층수를 구한다.
- 상자의 열 위치 (lastLCol)
- 일단 마지막상자 번호(n)와 최대 행의 수(w)를 나눈 나머지를 구한다.
- 나머지가 0인 경우가 나오는데, 이는 최대 행의 수(w)의 배수라는 것을 의미한다. 그와 동시에 해당 줄의 최대값을 의미한다.
=> 그렇기에 마지막상자 번호(n)가 최대 행(w)의 배수일 경우엔, 마지막 상자 열 위치(lastCol)이 최대값이 될 수 있도록 최대 행(w)값을 준다. - 마지막으로, 왼쪽기준으로 마지막상자의 열 위치(lastLCol)를 구한다.
- 마지막상자가 위치한 행(lastRow)이 '홀수층'일 경우, 정방향이므로 lastRow 값 그대로 지정한다.
- 마지막상자가 위치한 행(lastRow)이 '짝수층'일 경우, 역방향이므로 최대 행(w)에서 lastRow를 빼준 값을 지정해줘야한다.
( ※ 여기에서 w에다가 1을 더해주는 이유는 열의 시작위치가 첫번째 1이기 때문이다! (ex. 달력 월 개수 구하기) )
② 꺼내려는 상자가 있는 위치 구하기
for(let numRow=0; numRow<lastRow; numRow++) {
if(((numRow)*w)+1<=num && num<=(numRow+1)*w) {
let numCol = num%w === 0 ? w : num%w;
let numLCol = numRow%2 === 0 ? numCol : (w+1)-numCol;
answer = lastRow - numRow;
if(lastRow%2 === 1 && lastLCol < numLCol) answer -= 1;
if(lastRow%2 === 0 && lastLCol > numLCol) answer -= 1;
break;
}
}
- 반복문을 이용해 모든 층을 순회하여 꺼내려는 상자(num)의 위치를 구한다. (for)
( 반복문의 범위 : 첫번째층(0) 이상 ~ 마지막층(lastRow) 미만 ) - 상자의 행 위치 (numRow)
- 조건문을 이용해 꺼내려는 상자(num)이 위치한 층을 찾아낸다. (if)
- 조건은 여러 행에 공통적으로 적용되는 상자번호 범위 규칙을 찾아내 작성하였다.
- 첫번째 행: 1 ≤ num ≤ 5 ======> 0w+1≤ num ≤ 1w
- 두번째 행: 6 ≤ num ≤ 10 ======> 1w+1≤ num ≤ 2w
- 세번째 행: 11 ≤ num ≤ 15 ======> 2w+1≤ num ≤ 3w
- 네번째 행: 16 ≤ num ≤ 20 ======> 3w+1≤ num ≤ 4w
…
=> 이를 통해, ( numRow*w ) + 1 ≤ num ≤ ( numRow+1 ) * w 라는 공통 조건을 유추해낼 수 있다.
- 상자의 열 위치 (numLCol)
- 꺼내려는 상자의 열 위치 구하는 방식 역시 위에 작성한 ⓛ번과 유사하다.
- 다른 점은 층의 홀수/짝수 여부를 구하는 조건식이 다르다는 점이다.
- 위에는 lastRow%2 === 1 일때 정방향인것으로 지정했지만, 여기서는 numRow%2 === 0 일때 정방향으로 지정했다는 점이 다르다.
=> 그 이유는 lastRow는 무조건 1(층)부터 시작하지만, numRow는 시작값이 0이기때문이다!
- 최종 제출 답(answer)
- (마지막 층에 상자의 개수가 다 있다는 전제 하에) 꺼내려는 상자(num)를 꺼내기위해 필요한 상자의 개수는
마지막 상자의 행 위치(lastRow) - 꺼내려는 상자의 행 위치(numRow) 이다. - 하지만 (위의 그림처럼) 마지막 층엔 상자가 다 존재하지 않는
예외적인 경우가 있다.
=> 그렇기에 다 존재하지 않는 경우에 따른 마지막 층에 놓인 상자를 제외시켜주는 연산식을 작성해줘야한다. - 예외적인 상황은 아래와 같다.
- 마지막 상자의 행 위치(lastRow)가 정방향일 경우, 마지막 상자의 열 위치(lastLCol)가 꺼내려는 상자의 열 위치(numLCol)보다 작을 경우
- 마지막 상자의 행 위치(lastRow)가 역방향일 경우, 마지막 상자의 열 위치(lastLCol)가 꺼내려는 상자의 열 위치(numLCol)보다 클 경우
이렇게 설명하면 이해가 안되니 그림을 이용하여 설명하면 아래와 같다.
- (마지막 층에 상자의 개수가 다 있다는 전제 하에) 꺼내려는 상자(num)를 꺼내기위해 필요한 상자의 개수는

∴ 그래서 위의 예외적인 경우엔 꺼내려는 상자의 맨 위에는 상자가 존재하지 않으므로 1을 빼줘야한다!!
- 최종 제출답(answer)에 값이 선언되면 break를 이용해 그 즉시 반복문을 멈춘다.
이것으로 코드 설명 끝..!
'자바스크립트 > 코딩테스트' 카테고리의 다른 글
| [Python] 쓱 최대로 할인 적용하기 (0) | 2025.03.24 |
|---|