Skip to content

Commit 4d9387b

Browse files
authored
Merge pull request #122 from BrianLusina/feat/data-structures-linked-list-reorder-list
feat(data structures, linked list) reorder list
2 parents fa51bf6 + fadd8c2 commit 4d9387b

13 files changed

+332
-54
lines changed

DIRECTORY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,16 @@
255255
* Singly Linked List
256256
* [Node](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/node.py)
257257
* [Single Linked List](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/single_linked_list.py)
258+
* [Single Linked List Utils](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/single_linked_list_utils.py)
258259
* [Test Singly Linked Delete](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_delete.py)
259260
* [Test Singly Linked List](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list.py)
260261
* [Test Singly Linked List Nth To Last](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_nth_to_last.py)
261262
* [Test Singly Linked List Pairwise Swap](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_pairwise_swap.py)
262263
* [Test Singly Linked List Remove Duplicates](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_remove_duplicates.py)
263264
* [Test Singly Linked List Remove Nth Last Node](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_remove_nth_last_node.py)
265+
* [Test Singly Linked List Reorder List](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_reorder_list.py)
264266
* [Test Singly Linked List Rotate](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_list_rotate.py)
267+
* [Test Singly Linked Merge And Weave](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_merge_and_weave.py)
265268
* [Test Singly Linked Move Tail To Head](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_move_tail_to_head.py)
266269
* [Test Singly Linked Palindrome](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_palindrome.py)
267270
* [Test Singly Linked Revese](https://github.com/BrianLusina/PythonSnips/blob/master/datastructures/linked_lists/singly_linked_list/test_singly_linked_revese.py)

datastructures/linked_lists/__init__.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,3 +715,36 @@ def pairs_with_sum(self, target: T) -> List[Tuple[Node, Node]]:
715715
List: list of pairs
716716
"""
717717
raise NotImplementedError("not yet implemented")
718+
719+
@staticmethod
720+
def reverse_list(head: Node) -> Optional[Node]:
721+
"""
722+
Reverses a linked list given the head node
723+
Args:
724+
head Node: the head node of the linked list
725+
Returns:
726+
Optional[Node]: the new head node of the reversed linked list
727+
"""
728+
if head is None or head.next is None:
729+
return head
730+
731+
# track previous node, so we can point our next pointer to it
732+
previous = None
733+
# track node to loop through
734+
current_node = head
735+
736+
while current_node:
737+
# track the next node to not lose it while adjusting pointers
738+
nxt = current_node.next
739+
740+
# set the next pointer to the node behind it, previous
741+
current_node.next = previous
742+
743+
# adjust the new previous node to the current node for subsequent loops
744+
previous = current_node
745+
746+
# move our node pointer up to the next node in front of it
747+
current_node = nxt
748+
749+
# return the new tail of the k-group which is our head
750+
return previous

datastructures/linked_lists/singly_linked_list/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,3 +592,29 @@ Here `n` is the number of nodes in the linked list
592592
- Stack
593593

594594
---
595+
596+
## Reorder List
597+
598+
Given the head of a singly linked list, reorder the list as if it were folded on itself. For example, if the list is
599+
represented as follows:
600+
601+
L0 -> L1 -> L2 -> L3 -> L4 -> L5
602+
603+
The reordered list should be:
604+
605+
L0 -> L5 -> L1 -> L4 -> L2 -> L3
606+
607+
You don’t need to modify the values in the list’s nodes; only the links between nodes need to be changed.
608+
609+
### Constraints
610+
611+
- The range of number of nodes in the list is [1, 500]
612+
- -5000 <= `node.value` <= 5000
613+
614+
### Examples
615+
616+
![Example 1](./images/examples/singly_linked_list_reorder_list_example_1.png)
617+
![Example 2](./images/examples/singly_linked_list_reorder_list_example_2.png)
618+
![Example 3](./images/examples/singly_linked_list_reorder_list_example_3.png)
619+
![Example 4](./images/examples/singly_linked_list_reorder_list_example_4.png)
620+
![Example 5](./images/examples/singly_linked_list_reorder_list_example_5.png)
23 KB
Loading
25.2 KB
Loading
26.2 KB
Loading
29.1 KB
Loading
31.6 KB
Loading

datastructures/linked_lists/singly_linked_list/single_linked_list.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
from datastructures.linked_lists.singly_linked_list.node import SingleNode
55
from datastructures.linked_lists import LinkedList, T, Node
66
from datastructures.linked_lists.exceptions import EmptyLinkedList
7+
from datastructures.linked_lists.singly_linked_list.single_linked_list_utils import (
8+
reverse_list,
9+
merge_and_weave,
10+
)
711

812

913
class SinglyLinkedList(LinkedList):
@@ -983,6 +987,36 @@ def reverse_list(head_node: SingleNode) -> SingleNode:
983987
def remove_tail(self):
984988
pass
985989

990+
def reorder_list(self) -> Optional[SingleNode]:
991+
"""
992+
Reorders the linked list in place.
993+
Returns:
994+
head node of reversed linked list
995+
"""
996+
# return early if there is no head node
997+
if self.head is None:
998+
return None
999+
1000+
# first split the linked list into two halves. To do this without knowing the length of the linked list beforehand
1001+
# we must first find the middle node. This uses the slow & fast pointer approach
1002+
middle_node = self.middle_node()
1003+
1004+
# Store the second half head node
1005+
second_half_head = middle_node.next
1006+
# cut the connection between the first half and the second half
1007+
middle_node.next = None
1008+
1009+
# Now, we need to reverse the second half of the linked list in place
1010+
# The reversal step involves taking the second half of the linked list and reversing it in place
1011+
# for example, if the linked list is 1 -> 2 -> 3 -> 4 -> 5, the second half is 3 -> 4 -> 5
1012+
# after reversing, it becomes 5 -> 4 -> 3
1013+
reversed_second_half = self.reverse_list(second_half_head)
1014+
1015+
# now we can merge and weave the first half and the reversed second half
1016+
reordered_list = merge_and_weave(self.head, reversed_second_half)
1017+
1018+
return reordered_list
1019+
9861020
def kth_to_last_node(self, k: int) -> Optional[SingleNode]:
9871021
"""
9881022
Gets the Kth to the last node.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from typing import Optional
2+
from datastructures.linked_lists.singly_linked_list.node import SingleNode
3+
4+
5+
def merge_and_weave(
6+
first_half_head: SingleNode, second_half_head: SingleNode
7+
) -> Optional[SingleNode]:
8+
"""
9+
Merges and weaves the first half and the reversed second half of the linked list in place.
10+
Args:
11+
first_half_head: head node of the first half of the linked list
12+
second_half_head: head node of the reversed second half of the linked list
13+
Returns:
14+
head node of the merged and weaved linked list
15+
"""
16+
if first_half_head is None or second_half_head is None:
17+
return None
18+
19+
p1 = first_half_head
20+
p2 = second_half_head
21+
22+
while p2:
23+
# save the pointer 1 next node to not loose it
24+
p1_next = p1.next
25+
p2_next = p2.next
26+
27+
# now we can move the pointers
28+
p1.next = p2
29+
p2.next = p1_next
30+
31+
p1, p2 = p1_next, p2_next
32+
33+
return first_half_head
34+
35+
36+
def reverse_list(head: SingleNode) -> Optional[SingleNode]:
37+
"""
38+
Reverses a linked list given the head node
39+
Args:
40+
head Node: the head node of the linked list
41+
Returns:
42+
Optional[Node]: the new head node of the reversed linked list
43+
"""
44+
if head is None or head.next is None:
45+
return head
46+
47+
# track previous node, so we can point our next pointer to it
48+
previous = None
49+
# track node to loop through
50+
current_node = head
51+
52+
while current_node:
53+
# track the next node to not lose it while adjusting pointers
54+
nxt = current_node.next
55+
56+
# set the next pointer to the node behind it, previous
57+
current_node.next = previous
58+
59+
# adjust the new previous node to the current node for subsequent loops
60+
previous = current_node
61+
62+
# move our node pointer up to the next node in front of it
63+
current_node = nxt
64+
65+
# return the new tail of the k-group which is our head
66+
return previous

0 commit comments

Comments
 (0)