Skip to content

Commit d747a68

Browse files
Add 'Reorder List'
1 parent 0e09f18 commit d747a68

File tree

6 files changed

+167
-2
lines changed

6 files changed

+167
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ A collection of LeetCode solutions
3838

3939
[Remove Nth Node From End of List](./src/remove_nth_node_from_end_of_list.py)
4040

41+
[Reorder List](./src/reorder_list.py)
42+
4143
[Reverse Linked List](./src/reverse_linked_list.py)
4244

4345
[Same Tree](./src/same_tree.py)

src/merge_two_sorted_lists.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,5 @@ def mergeTwoLists(self, list1: ListNode | None, list2: ListNode | None) -> ListN
7474
curr = curr.next
7575
# At this point, list1 or list2 may still have nodes. The non-null list
7676
# is attached to the end of the merged list at 'curr'.
77-
curr.next = list1 if list1 is not None else list2
77+
curr.next = list1 if list1 else list2
7878
return prehead.next

src/middle_of_the_linked_list.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
slow
2929
fast
3030
31-
When the list contains an even number of nodes, there are two middle nodes.
31+
If the list contains an even number of nodes, there are two middle nodes.
3232
To take the second middle node, use slow.next:
3333
3434
1 2 3 4 5 6

src/reorder_list.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
"""
2+
143. Reorder List
3+
4+
https://leetcode.com/problems/reorder-list
5+
6+
NOTES
7+
* This problem is a combination of three easy problems:
8+
* Middle of the Linked List
9+
* Reverse Linked List
10+
* Merge Two Sorted Lists
11+
12+
First, find the middle node. If the list contains an even number of nodes,
13+
take the second middle node. Next, reverse the second list. Finally, use
14+
the process for merging two sorted lists to stitch the lists back together.
15+
16+
Example (where ○ represents null):
17+
18+
Find the middle node:
19+
20+
1 2 3 4 5
21+
● → ● → ● → ● → ● → ○ middle = 3
22+
23+
m
24+
25+
Reverse the second list:
26+
27+
1 2 3 5 4
28+
● → ● → ● → ○ ● → ● → ○
29+
30+
m
31+
32+
Merge the two lists (starting with the head of the first list):
33+
34+
35+
1 2 3 2 3
36+
● → ● → ● → ○ ● → ● → ● → ○
37+
↑ 1 ↑
38+
○ ○ → ●
39+
↑ ↑
40+
5 4 5 4
41+
● → ● → ○ ● → ● → ○
42+
↑ ↑
43+
44+
45+
1 5 2 4 3
46+
● → ● → ● → ● → ● → ○
47+
48+
This is a tricky one and you just have to know what to do here. Once you know
49+
the solution, the implementation is trivial.
50+
"""
51+
52+
from src.classes import ListNode
53+
54+
55+
class Solution:
56+
def reorderList(self, head: ListNode | None) -> None:
57+
"""
58+
Do not return anything, modify head in-place instead.
59+
"""
60+
if not head:
61+
return None
62+
63+
# Find the middle node.
64+
m = self.middleNode(head)
65+
66+
# Create two lists by unlinking the node after the middle node.
67+
l1, m.next, l2 = head, None, m.next
68+
69+
# Reverse the second list.
70+
l2 = self.reverseList(l2)
71+
72+
# Merge the two lists (starting with the head of the first list).
73+
_ = self.mergeTwoLists(l1, l2)
74+
75+
return None
76+
77+
def middleNode(self, head: ListNode) -> ListNode:
78+
"""
79+
Given the head of a singly linked-list, return the middle node. If
80+
there are two middle nodes, return the second middle node.
81+
"""
82+
if not head:
83+
return head
84+
85+
slow, fast = head, head
86+
87+
while fast.next and fast.next.next:
88+
slow = slow.next
89+
fast = fast.next.next
90+
91+
# Handle odd and even lists.
92+
return slow.next if fast.next else slow
93+
94+
def reverseList(self, head: ListNode | None) -> ListNode | None:
95+
"""
96+
Given the head of a singly linked-list, reverse the list in-place and
97+
return the new head.
98+
"""
99+
prev = None
100+
curr = head
101+
# 1. Store the current node's reference to next.
102+
# 2. Update the current node's next to be the previous node.
103+
# 3. Update the previous node to be the current node.
104+
# 4. Update the current node to be the next node (stored in 1).
105+
while curr:
106+
_next = curr.next
107+
curr.next = prev
108+
prev = curr
109+
curr = _next
110+
return prev
111+
112+
def mergeTwoLists(self, list1: ListNode | None, list2: ListNode | None) -> ListNode | None:
113+
"""
114+
Given the head of two singly linked-lists, merge them starting with the
115+
head of the first list.
116+
"""
117+
prehead = ListNode(-1)
118+
curr = prehead
119+
# 1. Alternate between taking from list1 and list2.
120+
# 2. Update the current node's next to be either head of the two.
121+
# 3. Update the head of the list from which the node was taken.
122+
# 4. Update the current node in the merged list.
123+
i = 1
124+
while list1 and list2:
125+
if i % 2:
126+
curr.next = list1
127+
list1 = list1.next
128+
else:
129+
curr.next = list2
130+
list2 = list2.next
131+
curr = curr.next
132+
i += 1
133+
# At this point, list1 may still have nodes. If this is the case, list1
134+
# is attached to the end of the merged list at 'curr'.
135+
curr.next = list1 if list1 else None
136+
return prehead.next

src/reverse_linked_list.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,6 @@ def reverseList(self, head: ListNode | None) -> ListNode | None:
6969
curr.next = prev
7070
prev = curr
7171
curr = _next
72+
# A more elegant way using tuple unpacking:
73+
# curr.next, prev, curr = prev, curr, curr.next
7274
return prev

tests/test_reorder_list.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""
2+
143. Reorder List
3+
4+
https://leetcode.com/problems/reorder-list
5+
"""
6+
7+
from unittest import TestCase
8+
9+
from src.reorder_list import Solution
10+
11+
from .utils import create_linked_list_from_list, create_list_from_linked_list
12+
13+
14+
class TestSolution(TestCase):
15+
def test_1(self):
16+
exp = [1, 4, 2, 3]
17+
ll = create_linked_list_from_list([1, 2, 3, 4])
18+
Solution().reorderList(ll)
19+
assert create_list_from_linked_list(ll) == exp
20+
21+
def test_2(self):
22+
exp = [1, 5, 2, 4, 3]
23+
ll = create_linked_list_from_list([1, 2, 3, 4, 5])
24+
Solution().reorderList(ll)
25+
assert create_list_from_linked_list(ll) == exp

0 commit comments

Comments
 (0)