“This is the 8th day of my participation in the First Challenge 2022. For details: First Challenge 2022”
Reverse Linked List II
LeetCode Portal 92. Reverse linked list II
The title
Give you the head pointer to the singly linked list head and two integers left and right, where left <= right. Reverse the list node from position left to position right to return the reversed list.
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.
Example:
Input: head = [1.2.3.4.5], left = 2, right = 4
Output: [1.4.3.2.5]
Input: head = [5], left = 1, right = 1
Output: [5]
Copy the code
Constraints:
- The number of nodes in the list is n.
- 1 <= n <= 500
- -500 <= Node.val <= 500
- 1 <= left <= right <= n
Thinking line
Their thinking
How do we solve this problem?
The first thing we need to know is how to invert a linked list from beginning to end, and if you’re not sure how to do that you can refer to this video that I did on Station B and the link is here, right
Now that we know how to reverse a list from start to end, let’s assume that the left node is the head and the right node is the tail. We can reverse the list from left to right.
After reversing the left to right list, the question is how to get the reversed list chain to take the unreversed head and tail
We can consider the following cases:
Let’s start with the head:
- if
left ! = = 1
That means there is an uninverted head, and we record the position of the headpreLeftNode
After the flip is done, turn thepreLeftNode
It points to the flipped head, but the head of the whole list hasn’t changedhead
- if
left ===1
It means that there is no unreversed head, then the head has changed, and the head is reversed linked listreversed
In the head.
Let’s look at what happens at the tail:
- if
Right === end of the list
, indicates the linked list after inversionreversed
The tail is going to be the tail of our final list. Here we flip the linked listreversed
The tail of theleftNode
thenext
Pointer tonull
Otherwise the linked list will have loops. - if
right ! == end of the linked list
, indicates the linked list after inversionreversed
The tail needs to be linked to the original listrightNode
The next node of. Here we flip the linked listreversed
The tail of theleftNode
thenext
The pointer points to the next node in the original list.
At this point, we have completed the logic of flipping the list, and finally we can return the new header.
The following code
/** * Definition for singly-linked list. * class ListNode { * val: number * next: ListNode | null * constructor(val? : number, next? : ListNode | null) { * this.val = (val===undefined ? 0 : val) * this.next = (next===undefined ? null : next) * } * } */
function reverseBetween(head: ListNode | null, left: number, right: number) :ListNode | null {
let list = head;
let i = 0
let pre: ListNode | null; // The previous one in the rollover process
let next: ListNode | null; // The last one in the rollover process
let preLeftNode: ListNode | null; // The first node left in the original list
let leftNode: ListNode | null; // left the corresponding node
let rightNode: ListNode | null; // The node corresponding to right
let rNext: ListNode | null; // The next node corresponding to right in the original list
while (list) {
i++;
if (i === left - 1) preLeftNode = list;
if (i === left) {
pre = list;
leftNode = list;
next = pre.next;
}
if (i === right) {
rightNode = list;
if (list.next) rNext = list.next;
break;
}
list = list.next;
}
// Reverse the list from left to right
while(next && pre ! == rightNode) {const temp = next.next;
next.next = pre;
pre = next;
next = temp;
}
let newHead: ListNode | null;;
// Handle the header logic
if (preLeftNode) {
newHead = head;
preLeftNode.next = pre;
} else {
newHead = pre;
}
// Handle tail logic
if (rNext) {
leftNode.next = rNext;
}else {
leftNode.next = null;
}
return newHead;
};
Copy the code
This is my first version of the code, so how can we optimize the code for this idea?
To reduce the number of headers we can add a dummyHead to the list dummyHead so that our new head node always points to dummyhead.next.
And what about our tail point? We can observe that whether rNext points to NULL or there is a node, we just need to point the flipped node tail to rNext, so we can get a slightly optimized code, as shown below
function reverseBetween(head: ListNode | null, left: number, right: number) :ListNode | null {
const dummyHead = new ListNode(0);
dummyHead.next = head;
let i = 0
let pre: ListNode | null; // The previous one in the rollover process
let next: ListNode | null; // The last one in the rollover process
let preLeftNode: ListNode | null; // The first node left in the original list
let leftNode: ListNode | null; // left the corresponding node
let rightNode: ListNode | null; // The node corresponding to right
let rNext: ListNode | null = null; // The next node corresponding to right in the original list
if (left === 1) preLeftNode = dummyHead;
while (head) {
i++;
if (i === left - 1) preLeftNode = head;
if (i === left) {
pre = head;
leftNode = head;
next = pre.next;
}
if (i === right) {
rightNode = head;
if (head.next) rNext = head.next;
break;
}
head = head.next;
}
// Reverse the list from left to right
while(next && pre ! == rightNode) {const temp = next.next;
next.next = pre;
pre = next;
next = temp;
}
preLeftNode.next = pre;
leftNode.next = rNext;
return dummyHead.next;
};
Copy the code
Time complexity analysis
O(n): where n is the total node of the list, and in the worst case, the entire list needs to be traversed.
This is my solution to this question. If you have any questions or better solutions, please leave a comment and interact.