There are three questions about inverting linked lists on Niuke, an introductory question, and there are many ways to invert linked lists. When I was doing the first question, I wrote a random one, and then I found out the method I used later, and I was doing the second question The third question was a bit cumbersome, so I considered the three questions together and chose a relatively clearer way of thinking. The three questions are solved using the same idea.
reverse linked list
topic
Reverse Linked List-Title link
Given a single linked list head node pHead (the head node has a value, for example, in the figure below, its val is 1), the length is n, after reversing the linked list, return the new linked list header.
train of thought
The method is to use three pointers to reverse the linked list pointing to the
cur pointer pointing to the current node, pre pointing to the predecessor, and temp pointing to the successor.
The operation is as shown in the figure:
In the initial state, pre is initialized to NULL
. Step 1: The pointer points back.
Step 2: Move the three pointers forward
. Then cycle through these two steps until the end to reverse the entire linked list.
Code
Time complexity: O(n)
Space complexity: O(1)
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
struct ListNode* cur =pHead;
struct ListNode* pre = NULL;
struct ListNode* temp = cur->next;
while(cur!=NULL){
cur->next = pre;
pre = cur;
cur = temp;
temp = temp->next;
}
return pre;
}
};
Invert the specified interval in the linked list
topic
Specified Interval Reversal - Topic Link
Reversing the interval between the m position and the n position of a linked list whose number of nodes is size requires time complexity O(n) and space complexity O(1).
train of thought
We first find the mth node, and then from m to n, we still use three pointers to invert it according to the idea of the previous question.
But it should be noted that it is not enough for us to just find the mth node, we should also keep the predecessor node of m, so that it is convenient to link back to the main chain after the inversion.
Therefore, when we traverse, we use cur as the traverse pointer and pre as the precursor pointer.
Since the head node has no predecessor, we add a virtual node to make the operation uniform without considering the special situation of the head node separately.
When we traverse to the mth node, pre remains unchanged at this time, and then use the cur pointer, p pointer and t pointer to perform the inversion operation. Reverse all the way to the nth node.
Then link the reversed linked list back to the main linked list.
As shown in the figure, it is the case of table length = 5, m = 2, and n = 4.
Another thing to note: according to this method, we can return to the head at the end. But there is a special case, if m=1, that is to say, the first one starts to reverse, then the node pointed to by head will be the last node after being reversed, so you can’t return head, you should return pre-> next. So this step in the code needs special handling.
the code
Time complexity: O(n)
Space complexity: O(1)
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
ListNode* reverseBetween(ListNode* head, int m, int n) {
// write code here
ListNode* pre = new ListNode(-1);
pre -> next = head;//增加一个前驱节点
ListNode* cur = head;
for (int i = 1; i < m; i++) {
pre = cur;
cur = cur->next;
}
ListNode* p = NULL;
ListNode* t = cur->next;
for (int i = m; i <= n; i++) {
cur->next = p;//回指
p = cur;
cur = t;
t = t->next;
}
pre->next->next = cur;//链接回主链
pre->next = p;
if (m == 1) head = pre->next;
return head;
}
};
The nodes in the linked list are reversed every k groups
topic
The nodes in the linked list are reversed every k groups-topic link
Flip the nodes in the given linked list every k groups, and return the flipped linked list
If the number of nodes in the linked list is not a multiple of k, keep the last remaining node as it is
You cannot change the value in the node, only change the node itself.
train of thought
According to the ideas of our previous two questions, we only need to use three conditions to reverse any linked list: the first node of the linked list to be reversed, the predecessor of the first node, and the number of reversals.
As shown in the figure, if we want to reverse this linked list, we only need to know these three conditions.
The code is as follows, which is basically the idea of the previous question:
void reverse(ListNode* pre, ListNode* cur, int k) {
ListNode* head = pre;//把头保留下来 反转后链接的时候需要用到
pre = NULL;//三个指针 开始反转
ListNode* t = cur->next;
for (int i = 1; i <= k; i++) {
//限制反转数量为k
cur->next = pre;
pre = cur;
cur = t;
t = t->next;
}
//反转后 链接回主链
head ->next->next = cur;
head->next = pre;
}
Then this operation is realized, and now the topic is simple, every group of k is reversed, we traverse the linked list, use a num to count when num=1,
record the predecessor pre and the current position cur, and then use it as num When it reaches k, it means that this section needs to be reversed.
We have the head node and its predecessor of this section of the linked list, so we can use this subfunction to achieve the reversal.
Suppose: k=4, then as shown in the figure, cur refers to the current node, which has reached the fourth one, cur_t and pre_t are the head and the precursor of the head of the linked list we saved, so we will give it to the
function , reverse, after the reverse is completed, as shown in the figure below.
There is one point to note here: before the reversal, cur points to the fourth node. Since the first four are reversed, after the reversal, cur should point to node 1.
So after inversion, we need to correct the pointing of cur. (Note that only the pointing of cur needs to be corrected, and pre does not need to be corrected, because after the reversal, node 4 has also been traversed, and the pointer will be moved back immediately, pre is directly equal to the corrected cur, and then cur can be moved backward .)
In addition, there is another problem, the same problem as the previous one, that is, the first set of inverted linked lists, the head needs to be reset, otherwise it will be wrong to return to the head.
the code
Time complexity: O(n)
Space complexity: O(1)
(In the worst case of this whole operation, it is equivalent to traversing the linked list twice, which is 2n, and the complexity is still O(n))
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
void reverse(ListNode* pre, ListNode* cur, int k) {
ListNode* head = pre;
pre = NULL;
ListNode* t = cur->next;
for (int i = 1; i <= k; i++) {
cur->next = pre;
pre = cur;
cur = t;
t = t->next;
}
//反转后 连接回主链
head ->next->next = cur;
head->next = pre;
}
ListNode* reverseKGroup(ListNode* head, int k) {
// write code here
ListNode* pre = new ListNode(-1);
pre->next = head; //增加一个新的结点
ListNode* cur = head;
ListNode* cur_t = NULL;//保存待反转链表的头和前驱
ListNode* pre_t = NULL;
int flag = 1;//标记 第一组反转时 需将head重置
int num = 1;
while (cur != NULL) {
if (num == 1) {
//保存待反转链表的头和前驱
cur_t = cur;
pre_t = pre;
}
if (num % k == 0) {
if (flag) {
//第一次反转
head = cur;
flag = 0;
}
reverse(pre_t, cur_t, k);
//反转完成后 纠正cur指针位置
cur = cur_t;
num = 0;//计数置0
}
pre = cur;
cur = cur->next;
num++;
}
return head;
}
};