Algorithms
[LeetCode] 143. Reorder List 풀이 (Java)
작은별._.
2026. 2. 11. 22:58
728x90
반응형
✔️ 오늘의 리트코드 공부 기록 – Reorder List
문제 요약 (Reorder List)
단일 연결 리스트가 주어졌을 때,
L0 → L1 → L2 → … → Ln을
L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …형태로 재배치하라.
값을 바꾸는 것이 아니라 노드 자체의 연결을 변경해야 한다.
문제링크: https://leetcode.com/problems/reorder-list
🤔 처음 떠올린 아이디어
문제를 보자마자 이런 생각이 들었다.
앞에서 하나, 뒤에서 하나씩 꺼내면 되지 않나?
예시:
1 → 2 → 3 → 4 → 5
→ 1, 5, 2, 4, 3
문제는 여기서 시작된다.
단일 연결 리스트는 뒤에서 접근할 수 없다.
배열이라면 left, right 포인터로 쉽게 해결되는데, 리스트는 뒤로 못 간다.
그래서 자연스럽게 이런 선택지가 떠올랐다:
- 스택을 써서 뒤에서 꺼내기
- 리스트를 reverse 해서 뒤를 앞으로 가져오기
💡 첫 번째 방법: Stack 사용
🧠 사고 과정
뒤에서 접근 못 한다 → 그럼 뒤에서 접근 가능하게 만들면 되지 않나?
→ 스택에 다 넣으면 마지막부터 꺼낼 수 있다.
즉,
- 모든 노드를 stack에 push
- 앞에서부터 순회하면서 stack.pop()으로 tail 연결
코드 (Java)
- 장점: 직관적, 구현 쉽다
- 단점: 추가 공간 사용, Linked List 패턴 문제로 보기엔 약간 아쉽다
class Solution {
public void reorderList(ListNode head) {
if (head == null) return;
Stack<ListNode> stack = new Stack<>();
ListNode curr = head;
// 모든 노드 stack에 저장
while (curr != null) {
stack.push(curr);
curr = curr.next;
}
curr = head;
int size = stack.size();
// 절반만 처리하면 됨
for (int i = 0; i < size / 2; i++) {
ListNode tail = stack.pop();
ListNode next = curr.next;
curr.next = tail;
tail.next = next;
curr = next;
}
curr.next = null; // 마지막 정리
}
}
📈 시간 / 공간 복잡도
- 시간: O(n)
- 공간: O(n) (stack 사용)
🔥 두 번째 방법: Reverse + Merge (정석 풀이)
🧠 Reverse 아이디어는 어떻게 떠올릴까?
우리는 이렇게 만들고 싶다: 앞쪽 절반 + 뒤쪽 절반 (역순)
예시:
1 → 2 → 3 → 4 → 5
이걸 머릿속에서 이렇게 쪼갠다:
(1 → 2 → 3) + (4 → 5)
그리고 뒤쪽을 뒤집으면:
(1 → 2 → 3) + (5 → 4)
이제 두 리스트를 번갈아 merge하면 된다.
즉 이 문제는 사실:
- 중간 찾기
- 뒤쪽 reverse
- 교차 merge
이 3단계 문제다.
💡 핵심 깨달음
단일 연결 리스트에서:
- 중간 찾기 → slow / fast
- 뒤에서 접근 → reverse
- 번갈아 연결 → merge
이건 Linked List 패턴 문제였다.
🧠 1️⃣ slow / fast 로 중간 찾기
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
왜 가능한가?
- fast는 2칸씩 이동
- slow는 1칸씩 이동
- fast가 끝에 도달하면 slow는 정확히 중간
🧠 2️⃣ 뒤쪽 reverse
여기서 reverse를 떠올리는 이유는 단 하나다.
단일 연결 리스트는 뒤로 못 간다.
그럼 뒤를 앞으로 가져오면 된다.
ListNode prev = null;
ListNode curr = slow.next;
slow.next = null; // 반드시 끊어야 함
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
이제 prev가 reverse된 두 번째 리스트의 head다.
🧠 3️⃣ 교차 merge
- first: 1 → 2 → 3
- second: 5 → 4
번갈아 연결:
ListNode first = head;
ListNode second = prev;
while (second != null) {
ListNode tmp1 = first.next;
ListNode tmp2 = second.next;
first.next = second;
second.next = tmp1;
first = tmp1;
second = tmp2;
}
✅ 전체 코드 (Java)
class Solution {
public void reorderList(ListNode head) {
if (head == null || head.next == null) return;
// 1. 중간 찾기
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 2. 뒤쪽 reverse
ListNode prev = null;
ListNode curr = slow.next;
slow.next = null;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
// 3. merge
ListNode first = head;
ListNode second = prev;
while (second != null) {
ListNode tmp1 = first.next;
ListNode tmp2 = second.next;
first.next = second;
second.next = tmp1;
first = tmp1;
second = tmp2;
}
}
}
📈 시간 / 공간 복잡도
- 시간: O(n)
- 공간: O(1)
📝 이번 문제에서 얻은 깨달음
- 단일 연결 리스트에서 “뒤에서 접근”은 항상 reverse를 떠올리자
- slow/fast는 “중간”이 보이면 자동 반응
- Linked List 문제는 결국 패턴 조합 문제
728x90
반응형