Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- 쉬움
- DP
- 문자열
- 미디움
- Depth-first Search
- Python
- Binary
- binary search
- 재귀
- hash table
- linked list
- two pointers
- HashTable
- matrix
- 리트코드
- sorting
- list
- 이진트리
- leetcode
- backtracking
- math
- string
- Medium
- tree
- easy
- 중간
- dfs
- Array
- binary tree
- recursive
Archives
- Today
- Total
부부의 코딩 성장 일기
LeetCode 143(Reorder List, Python) 본문
1. 문제 링크
2. 문제 설명
- linked list의 head가 주어졌을 때, 해당 list를 아래처럼 표현할 수 있다.
- L0 → L1 → ... → Ln-1 → Ln
- 이 때, 아래의 형태가 되도록 list를 reorder해라.
- L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → ...
- 여기서 node의 value자체를 수정하는 것이 아니라, node의 연결관계를 바꿔야 한다.
- 예시1)
- head가 [1,2,3,4]로 1→2→3→4의 연결관계를 가지고 있다면,
- 1→4→2→3으로 변경할 수 있다. output = [1,4,2,3]
- 예시2)
- head가 [1,2,3,4,5]로 1→2→3→4→5의 연결관계를 가지고 있다면,
- 1→5→2→4→3으로 변경이 된다. output = [1,5,2,4,3]
3. 처음 풀이
- 결국 더 좋은 방법을 찾지 못해서, time limit에 걸린채로 마무리하고.. 다른 풀이를 참고하였다.
- a,b,c 세개의 커서를 만들어주고, c는 가장 오른쪽으로 옮겨서 가장 끝의 노드로 위치시킨다음에,
- a.next에 c를 붙이고, 그 next에 b를 붙이는 방식을 반복하였다.
- [1,2,3,4,5]가 있을 때, 각 Iteration을 돌때마다 아래처럼 head의 연결관계가 변경이 된다.
- [1,5,2,3,4]
- [1,5,2,4,3]
- 하지만 여기서 문제는,, iteration돌 때마다, 계속 while문으로 c를 맨 끝으로 이동시켜야 하고,
- node를 많이 가지고 있는 head에 대해서는 너무 비효율적이다. 12개 test중에 1개 통과를 못했는데,, 그것의 head는 아래처럼 생겼다. 아래는 time limit 걸린 로직
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reorderList(self, head: Optional[ListNode]) -> None:
"""
Do not return anything, modify head in-place instead.
"""
if not head:
return head
if not head.next:
return head
a,b,c= head,head.next,head
c_distance =0
while c.next:
c = c.next
c_distance += 1
while b.next:
a.next = c
c.next = b
a=b
b=b.next
c_count = 0
while c_count < c_distance-1:
c = c.next
c_count +=1
c_distance = c_count-1 # reset c_distance
c.next = None
4. 다른 풀이
- 결국 다른 풀이를 참고하게 되었다. 3가지 step으로 나눠서 코드를 작성하는데, 이것 모두 linked list에서 배운 것들이다.
- 그것들을 총집합시킨 문제..였다.
- step1) slow, fast를 통해 head의 중간 node를 찾는다. [1,2,3,4,5,6]이라면, slow node의 head가 4에 위치할 수 있도록
- step2) [1,2,3], [4,5,6] 두개로 분리하고, 두번째 list에 대해 거꾸로 뒤집는다. [1,2,3], [6,5,4]가 될 수 있도록
- Revsered Linked List: https://codingbubu.tistory.com/99
- step3) 분리된 [1,2,3], [6,5,4] linked list에 대해
- 1→6→2→5→3→4가 되도록 연결관계를 짓는다.
- step1) find middle
- slow, fast = head, head로 저장하고,
- slow는 한칸씩 next로 이동시키고
- fast는 두칸씩 next에 이동시키다 보면 slow는 중간 지점으로 이동이 된다.
- slow, fast = head, head로 저장하고,
- step2) reverse second half
- 뒤집은 것은 아직도 약간 헷갈리는데 아래 그림을 보면 이해가 쉽다.
- 결국 앞에 None을 하나 만들어서 None→1→2→3→4→5 가 5→4→3→2→1→None이 되도록 작업하는 것.
- step3) merge lis
- 분리된 [1,2,3], [4,5,6]을 각각 head1, head2라고 하였을 때,
- head1의 다음 노드를 nxt에 keep해두고,
- head1의 다음노드를 head2로 설정하여, 연결리스트를 병합한 뒤,
- head1를 head2로 이동을 시켜서, 다음 iteration에서 head1이 새로운 연결리스트의 끝을 가리키도록 한다.
- 그리고 head2를 다음 노드로 이동시켜서, 다음 iteration에서 head2가 새로운 연결리스트의 끝을 가리키도록 한다.
- [1,2,3], [4,5,6]이 다음과 같이 반복이 되면,
- 첫 iteration에서 head1: 1→6→2→3, head2: 5→4
- 두번째 iteration에서 head1: 1→6→2→5→3, head2: 4
- 마지막 iteration에서 head1: 1→6→2→5→3→4, head2: None이되고,
- while문이 head2가 존재할 때까지만 반복하므로 iteration이 종료된다.
- 분리된 [1,2,3], [4,5,6]을 각각 head1, head2라고 하였을 때,
class Solution:
def reorderList(self, head):
if not head:
return
#step 1: find middle
slow, fast = head, head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
#step 2: reverse second half
prev, curr = None, slow.next
while curr:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
slow.next = None
#step 3: merge lists
head1, head2 = head, prev
while head2:
nxt = head1.next
head1.next = head2
head1 = head2
head2 = nxt
5. 배운 점
- linked list에서 가장 헷갈렸던 부분이 아래처럼 구현하는 부분이었는데
- nxt = head1.next
- head1.next = head2
- nxt = head1.next는 그냥 'node'가 이동이 된다고 생각하고,
- head1.next = head2는 연결관계인 화살표가 바뀐다고 생각하니 편했다.
- 이번 문제에서도 [1,2,3], [4,5,6]에 대해서 아래처럼 위 아래로 두고, 위에 nxt, h1, h2의 위치를 옮기고, next를 쓰면 화살표를 이동하는 구조로 작성하니 좀 더 이해가 쉬워졌다.
- [1,2,3]
- [4,5,6]
'Algorithm > LeetCode' 카테고리의 다른 글
LeetCode 383(Ransom Note, Python) (0) | 2024.03.31 |
---|---|
LeetCode 146(LRU Cache, Python) (0) | 2024.03.30 |
LeetCode 142(Linked List Cycle II, Python) (0) | 2024.03.28 |
LeetCode 374(Guess Number Higher or Lower, Python) (0) | 2024.03.27 |
LeetCode 139(Word Break, Python) (0) | 2024.03.26 |