题目链接如下:
leetcode92.反转链表||https://leetcode.cn/problems/reverse-linked-list-ii/submissions/386694465/
给你单链表的头指针 head
和两个整数 left
和 right
,其中 left <= right
。请你反转从位置 left
到位置 right
的链表节点,返回 反转后的链表 。
示例 1:
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
示例 2:
输入:head = [5], left = 1, right = 1
输出:[5]
提示:
n
1 <= n <= 500
-500 <= Node.val <= 500
1 <= left <= right <= n
用自己的话解释题意
在一个给定的链表里,把[left,right]的区间里的链表反转过来,并且重新连接到链表里。
ok
开始思考解决方法:
刚开始的第一印象是昨天的反转链表的题,即leetcode206.反转链表题解
在写的过程中,发生了亿点事情。
链表的题细节方面我觉得不是很好处理。
相比于leetcode206.反转链表题解不同的是:
1、此题我们需要对一个链表片段进行反转。
2、我们对片段处理完了之后,还需要将其重新连接到链表之中。
3、如何在一个反转部分的链表里准确找到新的头结点。
我们分步骤解决。
首先第一个问题,可以针对于需要处理的片段,通过确定待处理链表的长度和位置,来实现精准局部反转。
具体实现即for(int i=0;i
第二个问题:如何把处理好的链表连接回去
我们可以记录一下在[left,right]区间外紧邻left和right的那两个元素,因为这两个元素的链没有改变 ,所以直接改next值即可。
我们具体实现时用到的是:p0作为left左边的元素指针。因为反转之后,我们需要把p0的next连接到末尾的pre位置。同时把p0->next的next和区间外右边第一个元素相连。
如图所示:
第三个问题:
因为我们在这个更改过程中,如果涉及到了初始head的变化,那我们头指针位置就会发生改变。
那新的位置则是我们改变的链表片段的末尾置。那我们如何解决呢?
这里用到了一个虚拟指针vir。
我们把虚拟指针指向head。那么无论是head改变与否,p0是在哪里。我们的vir一直没有改变,那么Vir的next一直是头节点。
那么具体实现是在以下。
代码片段:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode *vir=new ListNode(0,head),*p0=vir;//vir是一个虚拟节点,方便后期寻找头节点,p0则是一个left左边的一个邻接指针。
ListNode *cur,*pre,*nxt;
//确定left前的位置。即p0;
for(int i=0;inext;
cur=p0->next;
pre=p0;
//经典的反转算yin法
for(int i=0;inext;
cur->next=pre;
pre=cur;
cur=nxt;
}
//将反转后的片段连到原先的链表里
p0->next->next=cur;
p0->next=pre;
return vir->next;
}
};
题目链接如下:
力扣25. K 个一组翻转链表https://leetcode.cn/problems/reverse-nodes-in-k-group/description/
给你链表的头节点 head
,每 k
个节点一组进行翻转,请你返回修改后的链表。
k
是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k
的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 1:
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例 2:
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
提示:
n
1 <= k <= n <= 5000
0 <= Node.val <= 1000
用自己的话解释题意:
把一个链表,每k个一组进行反转,最后剩下的如果不到k个,最后这几个则无需进行反转。
这一题,其实就是上一题(力扣92)的plus版本
但终究来说是同源。
所以我们开始找不同。
这一题的反转次数不再是1次了。而是变成多次-----那我们相对应的只要把计算出来有多少次,并且认为每一次都是一个上一题(力扣92)。那这样就可以啦。
具体细节是看以下代码实现:
讲解的话和上面一样,可以重新阅读一下上面的部分
代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode *reverseKGroup(ListNode *head, int k) {
int n=0;
for (ListNode *cur=head;cur;cur=cur->next)++n; // 统计节点个数
ListNode *vir=new ListNode(0, head), *p0=vir;
ListNode *pre=NULL,*cur=head,*nxt;
for (int i=1;i<=n/k;i++){
for (int i=0;inext;
cur->next=pre;
pre=cur;
cur=nxt;
}
nxt=p0->next;
p0->next->next = cur;
p0->next=pre;
p0=nxt;
}
return vir->next;
}
};
今天的题,怎么说呢
全是链表
原本最开始我是直接做的力扣25的那一道,但是我做着做着发现
就是在思考以及写程序的过程中,出现了很多不足。
发现自己思考的不是很完善,链表的细节处理还是很值得自己拿起来笔仔细推敲推敲的。
也推荐一下今天下午我在学习的过程中看的一个b站up主讲的课:反转链表又写错了?一个视频讲透!【基础算法精讲 06】反转链表 | 反转链表II | K个一组翻转链表 | 力扣 LeetCode 算法面试题_哔哩哔哩_bilibili