Problem of The Day: Reverse Linked List II
Problem Statement
Intuition
My initial thoughts are to traverse the list until the specified range, reverse that portion, and then connect it back to the original list.
Approach
I will use two pointers, prev
and curr
, to traverse the linked list until I reach the node at index left
. At this point, I’ll start reversing the nodes until I reach the node at index right
. I’ll also keep track of the nodes before and after the reversed portion. Finally, I’ll connect these nodes appropriately to ensure the reversed portion is integrated back into the original list.
Complexity
-
Time complexity: O(n)
-
Space complexity: O(1)
Code
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
if left is right:
return head
dummy = ListNode(-1, head)
prev_left = curr = head
left_node = right_node = None
prev = dummy
next_right = None
count = 1
while curr:
if count == left:
left_node = curr
prev_left = prev
if count == right:
right_node = curr
next_right = curr.next
prev = curr
curr = curr.next
count += 1
prev = None
curr = left_node
right_node.next = None
while curr is not None:
next_node = curr.next
curr.next = prev
prev = curr
curr = next_node
prev_left.next, left_node.next = right_node, next_right
return dummy.next
Editorial Solution
Approach 1: Recursion
class Solution:
def reverseBetween(self, head, m, n):
"""
:type head: ListNode
:type m: int
:type n: int
:rtype: ListNode
"""
if not head:
return None
left, right = head, head
stop = False
def recurseAndReverse(right, m, n):
nonlocal left, stop
# base case. Don't proceed any further
if n == 1:
return
# Keep moving the right pointer one step forward until (n == 1)
right = right.next
# Keep moving left pointer to the right until we reach the proper node
# from where the reversal is to start.
if m > 1:
left = left.next
# Recurse with m and n reduced.
recurseAndReverse(right, m - 1, n - 1)
# In case both the pointers cross each other or become equal, we
# stop i.e. don't swap data any further. We are done reversing at this
# point.
if left == right or right.next == left:
stop = True
# Until the boolean stop is false, swap data between the two pointers
if not stop:
left.val, right.val = right.val, left.val
# Move left one step to the right.
# The right pointer moves one step back via backtracking.
left = left.next
recurseAndReverse(right, m, n)
return head
- Time complexity: O(n)
- Space complexity: O(n)
Approach 2: Iterative Link Reversal
class Solution:
def reverseBetween(self, head, m, n):
"""
:type head: ListNode
:type m: int
:type n: int
:rtype: ListNode
"""
# Empty list
if not head:
return None
# Move the two pointers until they reach the proper starting point
# in the list.
cur, prev = head, None
while m > 1:
prev = cur
cur = cur.next
m, n = m - 1, n - 1
# The two pointers that will fix the final connections.
tail, con = cur, prev
# Iteratively reverse the nodes until n becomes 0.
while n:
third = cur.next
cur.next = prev
prev = cur
cur = third
n -= 1
# Adjust the final connections as explained in the algorithm
if con:
con.next = prev
else:
head = prev
tail.next = cur
return head
- Time complexity: O(n)
- Space complexity: O(1)