문제
https://school.programmers.co.kr/learn/courses/30/lessons/389478


풀이
class Solution {
public int solution(int n, int w, int num) {
// 상자는 번호가 1번부터 시작하지만, 컴퓨터는 0부터 세기 때문에
// 계산하기 편하게 num - 1을 해줌
// 예: 1번 상자는 0번째로, 7번 상자는 6번째로 생각
int floor = (num - 1) / w; // num이 몇 번째 층(0층부터)에 있는지
int pos = (num - 1) % w; // 그 층 안에서 왼쪽부터 몇 번째 칸인지 (0부터 시작)
// 층의 쌓이는 방향이 짝수층은 왼쪽→오른쪽, 홀수층은 오른쪽→왼쪽이라서
// 홀수층일 때는 좌우 순서를 반대로 바꿔줘야 함
// 예: w=6일 때, 1층은 12 11 10 9 8 7 순서이므로
// 오른쪽부터 0, 1, 2... 으로 번호가 매겨짐
int col = (floor % 2 == 0) ? pos : (w - 1 - pos);
// 전체 층 개수를 구함
// 예: 상자가 22개고 한 줄에 6개씩 놓으면 4층(0,1,2,3층)이 생김
// (22 + 6 - 1) / 6 은 올림 효과를 줘서 마지막에 덜 찬 층도 포함시킴
int totalFloors = (n + w - 1) / w;
// 자기 자신 상자도 꺼내야 하니까 처음부터 1개로 시작
int count = 1;
// 내 상자(num) 위에 있는 층들을 위에서부터 하나씩 확인
for (int f = floor + 1; f < totalFloors; f++) {
// f층의 첫 번째 상자 번호를 구함
// 예: 0층은 1번, 1층은 7번, 2층은 13번...
int start = f * w + 1;
// f층의 마지막 상자 번호를 구함
// 단, 마지막 층은 상자가 부족할 수도 있으니까 n을 넘지 않게 조정
// 예: (f+1)*w = 24지만 실제 상자는 22번까지면 22로 제한
int end = Math.min((f + 1) * w, n);
// 이 층에 실제로 몇 개의 상자가 있는지 계산
// 예: 13~18번 → 6개 (18 - 13 + 1)
int width = end - start + 1;
// 열(column) 계산
// 짝수층은 왼→오 방향이니까 그대로 col 사용
// 홀수층은 오→왼이라 col을 반대로 계산해야 함
// 단, 기준은 항상 한 줄 전체 크기(w)를 기준으로 해야 함
// (마지막 층처럼 상자가 적을 때도 열 위치 계산이 틀어지지 않게 하기 위해)
int boxCol = (f % 2 == 0) ? col : (w - 1 - col);
// 만약 이 층에 boxCol 위치가 실제로 존재하면 (즉, 상자가 있다면)
// 그 상자도 꺼내야 함
if (boxCol >= 0 && boxCol < width) {
count++;
}
}
// 꺼내야 하는 상자의 총 개수를 반환
return count;
}
}
코드 전체 흐름 설명
- num이 어느 층, 어느 칸에 있는지 계산
- / w → 몇 번째 층인지
- % w → 층 안에서 몇 번째 칸인지
- 층 방향이 바뀌면 칸 번호도 반대로 계산해야 함
- 전체 층 수 계산
- 마지막 층이 w개보다 적을 수 있으니까 올림 처리
- 위층부터 끝층까지 같은 열(column)에 있는 상자를 찾음
- 층마다 방향이 다르므로 열 번호를 다시 계산해야 함
- 마지막 층은 상자가 부족할 수 있으니 실제 상자 개수(width)로 범위를 제한
- 존재하는 상자만 count
이해 포인트 요약
| 코드 | 의미 | 이유 |
| (num - 1) | 번호를 0부터 맞춤 | 컴퓨터는 0부터 시작함 |
| / w | 몇 번째 층인지 | 한 층에 w개씩 있으니까 |
| % w | 층 안에서 몇 번째 칸인지 | 한 줄에서 나머지 칸 번호 |
| (w - 1 - pos) | 방향 반전 | 오른쪽→왼쪽으로 쌓일 때 |
| (n + w - 1) / w | 전체 층 개수 | 나누어떨어지지 않을 때 올림 처리 |
| Math.min((f + 1) * w, n) | 마지막 층 조정 | 상자가 부족할 수 있음 |
| if (boxCol < width) | 상자가 실제 존재하는 칸만 카운트 | 마지막 층은 폭이 작을 수 있음 |
public int solution(int n, int w, int num) {
// 입력값 의미
// n : 전체 상자 개수
// w : 한 줄(한 층)에 놓는 상자 개수
// num : 꺼내려는 상자의 번호
// cnt : 꺼내야 하는 상자 개수 (자기 자신 포함)
int cnt = 0;
// num은 현재 꺼내려는 상자 번호
// num이 n을 넘지 않을 동안 반복 (위층 상자가 남아 있는 동안)
while (num <= n) {
// (num - 1) % w : 현재 상자가 층 안에서 몇 번째 칸인지 (왼쪽부터 0 기준)
// (w - ((num - 1) % w) - 1) : 오른쪽 끝에서부터 몇 칸 떨어져 있는지
//
// (w - ((num-1) % w) - 1) * 2 + 1
// → 위층에 쌓인 상자 중 같은 열(column)에 있는 상자의 “번호 차이” 계산
// → 즉, 이 식만큼 더하면 바로 위층에 있는 같은 열의 상자 번호가 됨
//
// num += ... : 위층의 같은 column 상자 번호로 이동
num += (w - ((num - 1) % w) - 1) * 2 + 1;
// 꺼내야 하는 상자 하나 발견했으니 카운트 증가
cnt++;
}
// 결과 반환
return cnt;
}
이 코드가 하는 일
이 코드는 층을 직접 계산하거나 시뮬레이션하지 않고,
위층에 있는 같은 위치의 상자 번호를 직접 점프해서 찾는 방식
즉, “한 층 위에 같은 열에 있는 상자 번호가 얼마인지”를
수식으로 한 줄에 표현해 놓은 것
동작 예시 (n = 22, w = 6, num = 8)
| 반복 | num 값 | 의미 | 설명 |
| 시작 | 8 | 1층 | 처음 꺼낼 상자 |
| 1회차 | num += (6 - ((8-1)%6) - 1)*2 + 1 → 8 + (6-1-1)*2 + 1 = 8 + 9 = 17 | 2층의 같은 열 상자 | 17번 상자도 꺼내야 함 |
| 2회차 | num += (6 - ((17-1)%6) - 1)*2 + 1 → 17 + (6-4-1)*2 + 1 = 17 + 3 = 20 | 3층의 같은 열 상자 | 20번 상자도 꺼내야 함 |
| 3회차 | num = 20 + (...) → 20 + (6 - ((20-1)%6) - 1)*2 + 1 = 20 + 7 = 27 | 27 > n(22) | 반복 종료 |
결과: 꺼낸 상자 3개 (8, 17, 20)
왜 이런 식이 나왔는지
- (num - 1) % w
→ 현재 상자가 그 층에서 몇 번째 칸인지(0부터 센 위치) - (w - ((num - 1) % w) - 1)
→ 그 상자가 오른쪽 끝에서 얼마나 떨어져 있는지 - 그 값에 *2 + 1을 하는 이유
→ 상자는 왼→오, 오→왼으로 번갈아 쌓이니까
한 층 올라갈 때 반대쪽 끝으로 이동했다가 다시 같은 열로 돌아와야 함
(그래서 ‘왕복 거리 ×2 + 1칸’ 이동)
이걸 다 합치면 “위층의 같은 열 상자까지 건너뛰는 거리”가 됨
'Algorithm > Programmers' 카테고리의 다른 글
| [Programmers] Lv.1 | [PCCP 기출문제] 1번 / 동영상 재생기 | Java (0) | 2025.11.06 |
|---|---|
| [Programmers] Lv.1 | 유연근무제 | Java (0) | 2025.11.06 |
| [Programmers] Lv.0 | 중복된 숫자 개수 | Java (0) | 2025.11.06 |
| [Programmers] Lv.0 | 머쓱이보다 키 큰 사람 | Java (0) | 2025.11.06 |
| [Programmers] Lv.0 | 두 수의 합 구하기 | Java (0) | 2025.11.06 |
댓글