문제
| 주어진 연결 리스트에서 인접한 두 노드씩 교환한 후, 변경된 리스트의 헤드를 반환하라. 단, 노드의 값을 직접 바꾸면 안 되고, 노드 자체를 교환해야한다. |
https://leetcode.com/problems/swap-nodes-in-pairs/description/
public class SwapNodesInPairs {
public static class ListNode {
int val;
ListNode next;
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
public static void main(String[] args) {
ListNode node = new ListNode(1);
node.next = new ListNode(2);
node.next.next = new ListNode(3);
node.next.next.next = new ListNode(4);
node.next.next.next.next = new ListNode(5);
node.next.next.next.next.next = new ListNode(6);
ListNode result = swapNodesInPairs(node); // 구현
while(result != null) {
System.out.println(result.val);
result = result.next;
}
}
}
해결1) 반복문 사용
1-1) while문과 Dummy Node 사용 1
public static ListNode swapNodesInPairs(ListNode head) {
ListNode node = new ListNode(0);
node.next = head;
ListNode root = node;
while (node.next != null && node.next.next != null) {
ListNode a = node.next;
ListNode b = node.next.next;
// swap
a.next = b.next;
node.next = b;
node.next.next = a;
// move
node = node.next.next;
}
return root.next;
}
while문과 Dummy Node (= node, ListNode(0)) 을 사용하여 두 노드의 쌍을 swap 할 수 있습니다.
인자로 넘겨 받은 연결 리스트의 head 노드를 Dummy Node (node) 뒤에 연결하고
node 를 기준으로 그 다음 노드(a) 와 그 다음 다음 노드(b) 의 포인터를 swap 합니다.
swap 이 완료되면 다음 두 노드의 쌍을 swap 해야 하므로 두 노드 뒤로 이동합니다.
조금 더 구체적으로 이야기하면,
(1) a 노드의 다음을 b 노드의 다음으로 연결한다
(2) 기준 노드의 다음을 b로 연결한다
(3) 기준 노드의 다음 다음(b.next)을 a로 연결한다.
1-2) while문과 Dummy Node 사용 2
public static ListNode swapNodesInPairsAnotherAnswer(ListNode head) {
ListNode node = new ListNode(0);
node.next = head;
ListNode root = node;
while (node.next != null && node.next.next != null) {
ListNode a = node.next;
ListNode b = node.next.next;
// swap
a.next = b.next;
b.next = a;
node.next = b;
// move
node = node.next.next;
}
return root.next;
}
while 문과 Dummy Node(= node, ListNode(0)) 을 사용하여 swap 하는 또 다른 방식의 풀이입니다.
위 방식과 크게 다르지 않습니다. (순서만 다릅니다)
다만 swap 부분에서 node를 기준으로 연결 관계(=포인터)를 변경하는 것이 아니라,
a 노드와 b노드의 연결 관계를 swap 한 뒤(b -> a) 맨 앞의 기준 노드(node)의 다음을 b로 변경하는 것입니다.
구체적으로 살펴보면,
(1) a 노드의 다음을 b 노드의 다음으로 연결한다
(2) b 노드의 다음을 a 노드로 연결한다
(3) 기준 노드의 다음을 b 노드로 연결한다
그리고 동일하게 swap이 완료되면 두 노드 뒤로 이동합니다.
해결2) 재귀함수 사용
public static ListNode swapNodesInPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
// swap
ListNode tmp = head.next;
head.next = swapNodesInPairs(head.next.next); // recursive call
tmp.next = head;
return tmp;
}
while 문(반복문)을 사용하지 않고 재귀 함수를 사용하여 해결할 수도 있습니다.
코드만 봐서는 직관적으로 이해하기가 다소 어렵기 때문에 풀어서 설명하겠습니다.
| LinkedList
| 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> null |
| STEP1 : 시작
| head = 1, head.next = 2, swapNodesInPairs(3) |
tmp = head.next(2)
head(1).next = swapNodesInPairs(3) // ↖︎ 재귀 호출 결과 : 4 -> 3 -> 5 -> 6 -> null (* 1 -> 4 -> 3 -> 6 -> 5 -> null 완성 *)
| STEP2 : swapNodesInPairs(3) 내부 로직
| head = 3, head.next = 4, swapNodesInPairs(5) |
tmp = head.next(4)
head(3).next = swapNodesInPairs(5) // ↖︎ 재귀 호출 결과 : 6 -> 5 -> null (* 3 -> 6 -> 5 -> null 완성 *)
| STEP3 : swapNodesInPairs(5) 내부 로직
| head = 5, head.next = 6, swapNodesInPairs(null) |
tmp = head.next(6)
head(5).next = swapNodesInPairs(null) // ↖︎ 재귀호출 결과 : null (* 5 -> null 완성 *)
| STEP4 : swapNodesInPairs(null) 내부로직
| head = null |
if (head == null) -> return head // (null) 리턴 ↖︎
tmp(6).next = head(5)
return tmp // (6 -> 5 -> null) 리턴 ↖︎
tmp(4).next = head(3)
returm tmp // (4 -> 3 -> 6 -> 5 -> null) 리턴 ↖︎
tmp(2).next = head(1)
return tmp // 최종 결과로 (2 -> 1 -> 4 -> 3 -> 6 -> 5 -> null) 리턴
마무리하며
재귀 함수는 코드로 얼핏 보았을 때는 간단해보이지만, 한번에 생각해내거나 이해하기가 생각보다 까다로운 것 같습니다. 다음 함수 호출에 변수의 값은 어떻게 할당되고, 최종 리턴 값은 어떻게 만들어지는지 그리고 리턴 결과를 호출부에서 어떻게 활용하는지 그림으로 그려보는 것이 이해하는데 큰 도움이 되는 것 같습니다.
그리고 swap을 할 때에는 꼭 이전 변수의 값을 미리 담아둘 임시 변수가 필요하다는 것을 기억해두면 좋을 것 같습니다.
'PS > Leetcode' 카테고리의 다른 글
| 15. 세 수의 합(3 Sum) (0) | 2025.03.13 |
|---|