0206. Reversed Linked List#
Problem#
Given the head of a singly linked list, reverse the list, and return the reversed list.
Examples#
Example 1:
Input: head = [1,2,3,4,5]
Output: [5,4,3,2,1]
Example 2:
Input: head = [1,2]
Output: [2,1]
Example 3:
Input: head = []
Output: []
Constraints:#
The number of nodes in the list is the range [0, 5000].
-5000 <= Node.val <= 5000
Follow-up#
Analysis#
If swaping values in the nodes are allowed, we dont need swap nodes that requires the update of next
pointer.
However, if the value in a node is not writable, then we will have to swap nodes.
The following solutions swap nodes instead of only values.
Solution 1#
create a empty linked list to store reversed list
attach each node iteratively to the reversed list
the node is the head, pointing to the previous reversed list
Example:
list = [1,2,3,4,5]
step 0: new_head
step 1: node = 1, new_head.next = node -> reversed_list = [1]
step 2: node = 2, prev = new_head.next, new_head.next = node, node.next = prev -> reversed_list = [2, 1]
...
Solution 2#
# some definitions
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def list_to_linkedlist(list):
head = ListNode()
node = head
for v in list:
v_node = ListNode(v)
node.next = v_node
node = node.next
return head.next
def print_linkedlist(linked_list):
res = []
while linked_list:
res.append(linked_list.val)
linked_list = linked_list.next
print(res)
list = [1,2,3,4,5]
head = list_to_linkedlist(list)
print_linkedlist(head)
[1, 2, 3, 4, 5]
# solution 1: two pointers O(N) in time, and O(1) in space
# one for current node, and the other for previous node
# 1-2-3-4-5 -> 1-2-3-4-5 -> 2-1 3-4-5 -> 3-2-1 4-5 -> 4-3-2-1 5 -> 5-4-3-2-1
def solution(head):
# initialize current and previous pointer
prev, cur = None, head
# main loop
while cur:
# save for future use as the original link between cur and cur.next will be destroied later.
next = cur.next
cur.next = prev
# move forward
prev = cur
cur = next
return prev
#test
list = list_to_linkedlist([1,2,3,4,5])
print_linkedlist(solution(list))
list = list_to_linkedlist([5])
print_linkedlist(solution(list))
list = list_to_linkedlist([])
print_linkedlist(solution(list))
list = list_to_linkedlist([2,5])
print_linkedlist(solution(list))
[5, 4, 3, 2, 1]
[5]
[]
[5, 2]
# solution 2: how to use two pointer method with a dummy node
# this method actually complicates the solution compared with solution 1
def solution(head):
# add a dummy node the original list
dummy = ListNode(next=head)
prev, cur = dummy, dummy.next
tail = cur
while cur:
next = cur.next
cur.next = prev
prev = cur
cur = next
if tail:
tail.next = cur
return prev
#test
list = list_to_linkedlist([1,2,3,4,5])
print_linkedlist(solution(list))
list = list_to_linkedlist([5])
print_linkedlist(solution(list))
list = list_to_linkedlist([])
print_linkedlist(solution(list))
list = list_to_linkedlist([2,5])
print_linkedlist(solution(list))
[5, 4, 3, 2, 1]
[5]
[0]
[5, 2]
# solution 3: how to use a dummy node for this kind of problem O(N) in time and O(1)
# iteratively add the first node in the orignal list to the dummay list as the second node
def solution(head):
# add a dummy node for the linked list
# this is a typical approach when the head of the original list may be modified.
dummy = ListNode()
# initialize current and previous pointer
cur = head
# main loop
while cur:
# save for future use as the original link between cur and cur.next will be destroied later.
prev = dummy.next
dummy.next = cur
# move forward
cur = cur.next
dummy.next.next = prev
return dummy.next
#test
list = list_to_linkedlist([1,2,3,4,5])
print_linkedlist(solution(list))
list = list_to_linkedlist([5])
print_linkedlist(solution(list))
list = list_to_linkedlist([])
print_linkedlist(solution(list))
list = list_to_linkedlist([2,5])
print_linkedlist(solution(list))
[5, 4, 3, 2, 1]
[5]
[]
[5, 2]
# solution 2: iterative solution, which is same as previous solution except that the dummy node is not used here.
# [1-2-3-4-5] -> 1 -> 2-1 -> 3-2-1 -> 4-3-2-1 -> 5-4-3-2-1
def solution(head):
newHead = None
while head:
previous = newHead #4
newHead = head # 5
# update iterator
head = head.next # this has to be ahead of the next code
newHead.next = previous #
return newHead
#test
list = list_to_linkedlist([1,2,3,4,5])
print_linkedlist(solution(list))
list = list_to_linkedlist([5])
print_linkedlist(solution(list))
list = list_to_linkedlist([])
print_linkedlist(solution(list))
list = list_to_linkedlist([2,5])
print_linkedlist(solution(list))
[5, 4, 3, 2, 1]
[5]
[]
[5, 2]
# Solution 3; recursive solution
# 1-2-3-4-5 -> 5 -> 5-4 -> 5-4-3 -> 5-4-3-2 -> 5-4-3-2-1
def solution(head):
# return
if not head or not head.next:
return head
# update recusion
newHead = solution(head.next) # this newHead is always 5
head.next.next = head # why not newHead.next = next? because newHead is always 5, update newHead.NEXT will be liking removing the resest after 5.
head.next = None
return newHead
#test
list = list_to_linkedlist([1,2,3,4,5])
print_linkedlist(solution(list))
[5, 4, 3, 2, 1]