链表解题实例
1.力扣92.反转链表II
本题采用递归法求解。其c++代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution
{
public:
ListNode* successor = NULL;
ListNode* reverse(ListNode* head,int N)
{
//base case;即讨论最简单子问题,此时最简单问题为前1个链表进行反转,此时需要记录后驱结点。
if(N==1)
{
successor = head->next;
return head;
}
//递归
//(1)向子问题寻求结果
ListNode* Last = reverse(head->next,N-1);
//(2)对每一层递归作相应处理
head->next->next = head;
head->next = successor;
//(3)返回当层递归结果
return Last;
}
public:
ListNode* reverseBetween(ListNode* head, int m, int n)
{
//base case;即讨论最简单子问题的情况下,此时最简单子问题转化为求解链表前n个元素的反转。
if (m==1)
{
return reverse(head,n);
}
//递归操作步骤:
//(1)询问子问题的结果,并将其保存在head后的链表中
head->next = reverseBetween(head->next,m-1,n-1);
//(2)返回当前结果
return head;
}
};
2.力扣141.环形链表
(1)采用递归方法进行求解
c++代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head)
{
//base case
if (head==NULL||head->next==NULL)
return false;
if (head==head->next)
return true;
//递归过程
//这里需要提前记录下head的后一结点,因为后面会改变head的指针
ListNode* breaker=head->next;
head->next = head;
//这里不能适用hasCycle(head.next),因为此时head的指针已经改变。
return hasCycle(breaker);
}
};
这里与上述递归三部曲的一些小区别在于这里需要破坏链表的结构,因此在获取子问题的解时,需要提前使得所经历的结点产生自环。因此base case为当存在自环连边时,返回true。
(2)双指针法(快慢指针法)
//快慢指针法
class Solution {
public:
bool hasCycle(ListNode *head)
{
if (head==NULL)
return false;
ListNode * point1 = head;
ListNode * point2 = head;
while(point2->next!=NULL and point2->next->next!=NULL)
{
point1 = point1->next;
point2 = point2->next->next;
if (point2==point1)
return true;
}
return false;
对于环形“跑道”来说,只要二者速度不同,最终一定会相遇。这一题正式利用了上述思想。
3.力扣237题
这一题比较简单,是常见的删除单链表的某个结点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution
{
public:
void deleteNode(ListNode* node)
{
ListNode* s=node->next;
node->val = s->val;
node->next = s->next;
}
};
4.力扣25题(困难题)
/**
* 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:
//对链表的反转-递归法和三指针法任选一种,都是返回反转链表的头结点
//(1)递归法
ListNode* reverse(ListNode* head,ListNode* tail)
{
if(head==tail)
{
return head;
}
ListNode* last = reverse(head->next,tail);
head->next->next=head;
head->next=NULL;
return last;
}
//(2)三指针法
ListNode* reverse(ListNode* head,ListNode* tail)
{
ListNode* pre,*cur,*nxt;
if(head==NULL)
return NULL;
pre = NULL;
cur = head;
while(cur!=tail)
{
nxt = cur->next;
cur->next = pre;
pre = cur;
cur = nxt;
}
cur->next=pre;
return cur;
}
//K个链表为一组进行反转;
ListNode* reverseKGroup(ListNode* head, int k)
{
if(head==NULL)
return NULL;
ListNode*a = head;
ListNode*b = head;
//利用双指针遍历长度为k的链表
for(int i=0;i<k-1;i++)
{
b = b->next;
//base case
if(b==NULL)
return a;
}
//递归法
ListNode* c=b->next;
ListNode* newNode=reverse(a,b);
a->next=reverseKGroup(c,k);
return newNode;
}
};
5.力扣第2题
利用pre结点与nxt结点解决问题的方法
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2)
{
ListNode* point1 = l1;
ListNode* point2 = l2;
ListNode* hair = new(ListNode);
ListNode* point3 = hair;
int add = 0;
while(point1!=NULL || point2!=NULL)
{
ListNode* nxt = new(ListNode);
point3->next = nxt;
point3 = nxt;
int n1 = point1?point1->val:0;
int n2 = point2?point2->val:0;
point3->val = n1 + n2 + add;
if(point3->val>=10)
{
add=1;
point3->val = point3->val-10;
}
else
add = 0;
if (point1)
point1 = point1->next;
if (point2)
point2 = point2->next;
}
if(add==1)
{
point3->next = new ListNode(1);
}
return hair->next;
}
};
这一题几个小技巧提醒一下:
//当结点为空时以0进行相加,当结点不为空时以结点值进行相加。
int n1 = point1?point1->val:0;
int n2 = point2?point2->val:0;
这里采用hair结点是为了保证在最开始的结点相加过程中产生一条连边,如果不采用hair结点时,就没办法保证在第一次结点相加时,实际上只需要一个结点。这一题还可以通过记录尾结点的方式进行解决。
ListNode* point3 = hair;
ListNode* nxt = new(ListNode);
point3->next = nxt;
point3 = nxt;
利用头结点与尾结点解决问题的代码
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2)
{
ListNode* head = NULL;
ListNode* tail = NULL;
int add = 0;
while(l1!=NULL || l2!=NULL)
{
int n1 = l1?l1->val:0;
int n2 = l2?l2->val:0;
int sum = n1 + n2 + add;
add = sum/10;
if(!head)
{
head = tail = new ListNode(sum%10);
}
else
{
tail->next = new ListNode(sum%10);
tail = tail->next;
}
if (l1)
l1 = l1->next;
if (l2)
l2 = l2->next;
}
if(add==1)
{
tail->next = new ListNode(1);
}
return head;
}
};
6.力扣第6题
这一题比较简单,采用常见的递归法就可以了。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
//base case
if(head==NULL)
return NULL;
if(head->next==NULL)
return head;
ListNode*nxt = head->next;
ListNode* last = swapPairs(head->next->next);
head->next=last;
nxt->next=head;
return nxt;
}
};