189. Rotate Array
2025-07-31
LeetCode 189번 풀이
이 글은 Obsidian에서 마이그레이션되었으며, 그 과정에서 AI의 도움을 받았습니다. 오류나 누락된 내용이 있다면 댓글로 알려주세요!
문제
풀이 1 - Brute Force
아이디어
문제 그대로 구현한다 (직관적이지만 unshift의 반복이…)
매번 배열의 마지막 요소를 꺼내 맨 앞에 넣음 (pop + unshift)
코드
function rotate(nums: number[], k: number): void {
for (let count = 0; count < k; count++) {
const back = nums.pop() as number; // pop한 원소를 도로 넣기 때문에 nums가 비어있는 경우는 없음 -> undefined가 반환되지 않는다.
nums.unshift(back);
}
}시간 / 공간 복잡도
- 시간 복잡도: (pop (
O(1)) + unshift(O(n))) × k →O(kn) - 공간 복잡도: 추가 공간을 필요로 하지 않는다 →
O(1)
풀이 2 - 보조 배열 사용하기
아이디어
회전하면 각 원소들의 인덱스가 바뀐다. nums = [1,2,3,4,5,6,7], k = 3 일 때 → [5,6,7,1,2,3,4]
- 1:
nums[0]→nums[3] - 2:
nums[1]→nums[4] - 3:
nums[2]→nums[5] - 4:
nums[3]→nums[6] - 5:
nums[4]→nums[0] - 6:
nums[5]→nums[1] - 7:
nums[6]→nums[2]
=> newIdx = (idx + k) % (nums.length) 요런 규칙이 있다!
In-place로 바꿔주기에는 너무 복잡하기 때문에 새로운 배열을 만들어주고, 기존 배열에 옮겨넣어주기 (문제에서 의도한 방법은 아닐듯)
코드
function rotate(nums: number[], k: number): void {
const length = nums.length;
const rotated = Array(length).fill(0);
nums.forEach((value, i) => {
const newIndex = (i + k) % length;
rotated[newIndex] = value;
});
rotated.forEach((newNum, idx) => {
nums[idx] = newNum;
});
}피드백
rotated를 생성할 때reduce를 썼다가 수정했다. reduce는 누적 계산이 목적인 메서드. 잘 알려진 메서드의 목적에 맞게 써야 가독성이 높아진다. (여기서 갑자기 왜 누적을 하지? 하면서 인지 비용이 증가하게 됨)
const rotated = nums.reduce((acc, cur, idx) => {
const newIdx = (idx + k) % length;
acc[newIdx] = cur;
return acc;
}, Array(length).fill(0))forEach보다는 for문이 빠르다. (참고: JS loop benchmark) 성능에 민감한 상황일 경우 for문을 고려하기
풀이 3 - 배열을 뒤집기 (In-place Reversal)
아이디어
nums = [1,2,3,4,5,6,7], k = 3 일 때 → [5,6,7,1,2,3,4]
이거를 자세히보면 뒤쪽 3개가 앞으로 왔고 (k개), 앞쪽 4개가 뒤로 왔다.
배열의 원소의 인덱스를 옮기면서 추가 메모리 공간을 사용하지 못하는 경우에는 값을 덮어쓰게 될 수 있어서 어려운데, 이 때 취할 수 있는 전략이 “배열을 뒤집기”
- 뒤에 있는 원소들이 앞에 왔으므로 일단 뒤집어준다. →
[7,6,5,4,3,2,1] - 가장 왼쪽에 있어야 하는 5가 제자리에 오도록 배열의 일부를 뒤집어준다 → 앞쪽 원소 3개(k개)를 다시 뒤집어준다 →
[5,6,7,4,3,2,1] - 남은 원소들도 원래 순서로 돌아가도록 뒤집어준다 → 뒤쪽 원소 4개(n-k개)를 다시 뒤집어준다 →
[5,6,7,1,2,3,4]
Javascript에는 배열을 일부만 뒤집는 메서드가 없기 때문에… 직접 구현해줘야 한다.
코드
function reverse(nums: number[], startIdx: number, endIdx: number): void {
while (startIdx < endIdx) {
[nums[startIdx], nums[endIdx]] = [nums[endIdx], nums[startIdx]];
startIdx++;
endIdx--;
}
}
function rotate(nums: number[], k: number): void {
const n = nums.length;
k = k % n; // n <= k 인 경우 대비
reverse(nums, 0, n - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, n - 1);
}