链表相关技巧
链表算法题技巧一般有增加头结点、使用快慢指针、递归的先序后序使用。本文主要为递归相关笔记。
链表翻转
leetcode206:反转链表
1.先序递归:双指针参数(增加NULL头结点,方便反转操作),每次更改一个方向,可直接转换成循环,书写正确率高,优先使用
class Solution{
public:
ListNode* reverseList(ListNode* head) {
if(!head) return NULL; //leetcode特殊样例处理
ListNode* pre = NULL;
return reverse(pre,head); //先序递归反转
}
ListNode* reverse(ListNode* pre,ListNode* cur){
if(cur==NULL) return pre;
ListNode* tmp = cur->next;//先序
cur->next = pre;//先序
return reverse(cur,tmp);//递归
}
};
// 1->2->3->4->5->null
// null 1->2->3->4->5->null 增加NULL头结点
// null<-1<-2<-3<-4<-5
2.后序递归:单指针参数,对递归思想的理解要求较高,书写易错
思想:长n链表反转问题可转化为长n-1链表反转,递归到长1后,回溯至长n
class Solution{
public:
ListNode* reverseList(ListNode* head) {
if(!head) return NULL;//leetcode样例空链表
//后序递归反转
if(!head->next) return head;//单个结点无需反转
ListNode* last = reverse(head->next);//递归
head->next->next = head;//后序
head->next = NULL;//后序
return last;
}
};
// 1->2->3->4->5->null
// 5->null
// 5->4->null
// ...
// 5->4->3->2->1->null
leetcode25:K个一组翻转链表
1.K个一组先序递归
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if(head==NULL) return NULL;
ListNode* a=head, *b = head;
for(int i=0;i<k;i++){
if(b==NULL) return head;
b= b->next;
}
ListNode* newhead = reverse(a,b);
a->next = reverseKGroup(b,k);
return newhead;
}
ListNode* reverse(ListNode* head,ListNode* b) {
if(head->next==b) return head;
ListNode* last = reverse(head->next,b);
head->next->next = head;
head->next = NULL;
return last;
}
};
leetcode92:反转链表II
1.后序递归(先序递归较为直观,省去)
class Solution {
public:
ListNode* successor = NULL;
ListNode* reverseBetween(ListNode* head, int m, int n) {
if(m==1){
return reverseN(head,n);
}
head.next = reverseBetween(head->next,m-1,n-1);
return head;
}
ListNode* reverse(ListNode* head,int n){
if(n==1){
successor = head->next;
return head;
}
ListNode* last = reverse(head->next,n-1);
head->next->next = head;
head->next = successor;
return last;
}
};