LC92. Reverse Linked List II¶
Problem Description¶
LeetCode Problem 92: Given the head
of a singly linked list and two integers left
and right
where left <= right
, reverse the nodes of the list from position left
to position right
, and return the reversed list.
Clarification¶
Assumption¶
Solution¶
Approach - Iteration¶
The problem can be solved using iterations. @hi-malik explains really well how to solve this problme using an iterative method. The basic idea is to reverse the node one-by-one by using 3 pointers, prev
, curr
, and forw
:
curr.next = forw.next
forw.next = curr.next or prev.next
, not sure and need to use an example to find whether to usecurr.next
orprev.next
prev.next = forw
forw = curr.next
Moreover, a dummy head is used to handle the case where left = 1
and prev
is assigned with the dummy head.
class Solution:
def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
dummy = ListNode(0, head)
prev = dummy
for i in range(left - 1): # 0 ~ left - 2
prev = prev.next # 1 ~ left - 1
curr = prev.next # left
for i in range(right - left):
forw = curr.next
curr.next = forw.next
forw.next = prev.next
prev.next = forw
return dummy.next
Complexity Analysis¶
- Time complexity: \(O(n)\)
Iteration through the list \(O(right)\) time and worst case \(O(n)\) - Space complexity: \(O(1)\)
Store 4 pointers (prev, curr, forw, and dummy)
Approach - Stack¶
Use stack to store the sublist that need to be reversed. After filling it up, then pop it up one by one and reverse the sublist easily. @vanAmsen provides a good solution on using stack.
In Python, using deque
is better than list
in expanding memory when growing stack.
from collections import deque
class Solution:
def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
dummy = ListNode(0, head)
prev = dummy
stack = deque()
for _ in range(left - 1):
prev = prev.next # prev: 1 ~ left - 1
current = prev.next # left
for _ in range(right - left + 1):
stack.append(current)
current = current.next
while stack:
prev.next = stack.pop()
prev = prev.next
prev.next = current
return dummy.next
Complexity Analysis¶
- Time complexity: \(O(n)\)
Need to go through the linked list in worst case, which takes \(O(n)\) time when right == n. - Space complexity: \(O(n)\)
Need \(O(n)\) space for stack.
Approach - Recursion¶
The problem can be solved using recursion but difficult to find clean solution. WarrenChen shares a recursive method that is relative easy to follow.
class Solution:
def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
if left == right:
return head
if left > 1:
head.next = self.reverseBetween(head.next, left - 1, right - 1) # head will be changed in side of the function
return head
else:
next = head.next
new_head = self.reverseBetween(next, 1, right - 1)
next_next = next.next
next.next = head
head.next = next_next
return new_head
Complexity Analysis¶
- Time complexity: \(O(n)\)
Need to do recursion \(O(right)\) time and worst case is \(O(n)\) when right == n. - Space complexity: \(O(n)\)
Need \(O(n)\) space to store recursion function call.
Comparison of Different Approaches¶
The table below summarize the time complexity and space complexity of different approaches:
Approach | Time Complexity | Space Complexity |
---|---|---|
Approach - iteration | \(O(n)\) | \(O(1)\) |
Approach - stack | \(O(n)\) | \(O(n)\) |
Approach - recursion | \(O(n)\) | \(O(n)\) |