2020-5-16每日一题
基础链表的反转(easy)
思路一:递归
(1)反转当前的链表等价于反转当前链表的第一个元素和除了第一个元素的剩下元素。
每一步的步骤都是(1),步骤相同,我们就考虑使用递归。
递归三要素:
- 明确这个递归函数要干什么(反转链表)
- 寻找递归结束条件
- 找出函数的等价关系式,不断缩小参数范围。
递归思路:
- 递归终止条件:当前节点为空或当前节点的next为空。
- 可以使数据规模变小的递归等价关系式:反转当前的链表等价于反转当前链表的第一个元素和除了第一个元素的剩下元素。
class Solution {
public:
// 1.递归方式
ListNode *reverse(ListNode *head){
//递归终止条件:
if(head==NULL||head->next==NULL){
return head;
}
//递归等价关系式。获得之后的递归完成的程序后。调整该head结点和通过递归已经反转过的链表的关系。
ListNode * tmp=reverse(head->next);
head->next->next=head;
head->next=NULL;
return tmp;
}
ListNode* reverseList(ListNode* head) {
ListNode *now;
now=reverse(head);
return now;
}
};
思路二:迭代
迭代的思路较为简单,因为单向链表不存在前向节点,所以我们通过节点本身找到其的前向节点。所以我们显式定义一个前向节点pre。
算法思路:
- 定义一个前向节点pre,和当前节点cur.
- 进入循环,每次循环结束时,可以使得当前节点cur的next指向前向节点pre.循环终止条件为当前节点cur为空。
- 我们改变了cur的next,怎样保证cur原先的next不会丢失? 显示定义一个Next节点即可。
代码
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *pre=NULL;
ListNode *cur=head;
while(cur!=NULL){
ListNode* Next=cur->next;
cur->next=pre;
pre=cur;
cur=Next;
}
return pre;
}
};
k个数据为一组的链表反转(hard)
思路分析:(这道题调bug调了好久,哭唧唧~)
这道题和反转链表的题目类似。关键是以k个为一组的链表之间的连接。
(k个为一组的链表内部的反转我们可以通过上面的问题来实现)。
具体思路:
- 制定链表的第一个结点为begin结点,遍历链表做计数,每计数到k的时候,就断开这个链表,这个链表的末尾结点为end结点,开始为这个[begin,end]链表做反转。
- 因为要断开这个链表,所以需要一个指针指向断开链表的下一个结点(nextbegin)。
- 反转完毕后记录这个链表的末尾结点(lastEnd),用于链接下一个反转后的结点,同时更新begin结点。
- 如果最后有剩余的结点(不够k个),直接让lestEend指向begin就好了。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
//思路 从0开始遍历链表 遇到k个 结点 就将这k个结点进行翻转。
//关键还是指针的指向问题。
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if(head==NULL){
return NULL;
}
int num=0;
ListNode *now=head;
ListNode *begin=head; //每k个一组的第一个。
ListNode *pre=NULL;
ListNode *lastEnd=head;
ListNode *nextbegin;
int count=1;
while(now!=NULL){
num++;
//遇到k个结点 开始进行翻转。
if(num==k){
ListNode *end;
end=now;
nextbegin=end->next;
// 在begin 和end 之间的链表进行交换
ListNode *cur=begin;
int i=0;
//将这k个结点断开,开始进行翻转操作
while(i<k){
ListNode *tmp=cur->next;
cur->next=pre;
pre=cur;
cur=tmp;
i++;
}
//这k个结点转向了.如果这是第一堆反转的,就让head指向反转后的头结点,否则让第一堆的末节点连接上这个结点。
pre=NULL;
if(count==1){
head=end;
}
lastEnd->next=end; //链接上一个k个结点的末尾和这个k个结点的反转后的头.
lastEnd=begin; //更新该结点。
begin=nextbegin;
num=0;
count++;
now=nextbegin;
continue;
}
now=now->next;
}
lastEnd->next=nextbegin;
return head;
}
};