“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情”
链表
struct ListNode {
int val;
ListNode* next;
};
一.单链表结构
1.寻找链表的中点 作为链表题中较为简单的题,中点问题无外乎就是用快慢指针来完成 当链表的个数为偶数时 对于快指针的next进行判断,则会使慢指针在mid前一个停下 对于快指针的next的next进行判断,则会使慢指针在mid前一个停下
ListNode* findlistmid(ListNode *root)//当链表的个数为偶数时返回mid前一个的值
{
ListNode* n1 = root,*n2=root;
while(n2->next!=nullptr&&n2->next->next!=nullptr)
{
n1 = n1->next;
n2 = n2->next->next;
}
return n1;
}
ListNode* FindListmid(ListNode* root)//当链表的个数为偶数时返回mid后一个的值
{
ListNode* n1 = root, * n2 = root;
while (n2 != nullptr && n2->next != nullptr)
{
n1 = n1->next;
n2 = n2->next->next;
}
return n1;
}
2.翻转链表 首先定义一个空的节点表示翻转后尾节点(原头节点指向位置) curr表示的是当前遍历的节点 prev表示的是当前节点的上一节点(也就是翻转后当前节点所指向的节点)
ListNode* TurnList(ListNode* root)
{
ListNode* prev = nullptr;
ListNode* curr = root;
while (curr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
二.双链表结构 判断两单链表是否相交 时间复杂度O(N) 空间复杂度O(1)
1.首先第一步需要判断的是两个链表是否是有环的 第一种方法:哈希表 判断节点地址是否在哈希表内注册判断链表有无环 第二钟方法:快慢指针(快慢指针的所在环内转的圈数少于两圈) (1).当快指针指向空->无环 (2).当快指针与慢指针相遇->有环(且将快指针返回开头(每次走一步),当再次相遇时,得到入环节点)
ListNode*FindListIncorporate(ListNode*node)
{
if(node==nullptr)return nullptr;
ListNode* slow;
ListNode* fast;
if(node->next!=nullptr)slow=node->next;
else return nullptr;
if(node->next->next!=nullptr)fast=node->next->next;
else return nullptr;
while(1)
{
if(fast==nullptr||fast->next==nullptr)return nullptr;
if(fast==slow)break;
fast=fast->next->next;
slow=slow->next;
}
fast=node;
while(fast!=slow)
{
fast=fast->next;
slow=slow->next;
}
return slow;
}
2.对两个链表的的有无环进行情况分类
(1).当两单链表都无环(如果相交,最后部分一定共有) 首先得到两链表的尾节点end1和end2和长度len1和len2 当end1!=end2时:无公共节点 当ende1==end2时:有公共节点 令长链表的头节点先出发走abs(len1-len2)再一起走 最终相遇的第一个节点为两链表第一个相交节点
优化:
对len1计算链表长度时 n++
对len2计算链表长度时 n--
最终n>0 len1长 n<0 len2长
ListNode* Ringlesslist(ListNode *node1,ListNode*node2)
{
ListNode *end1=node1,*end2=node2;
int n=0;
while(end1->next!=nullptr)
{
end1=end1->next;
++n;
}
while(end2->next!=nullptr)
{
end2=end2->next;
--n;
}
if(end1!=end2)return nullptr;
ListNode *shot=n>0?node2?node1;
ListNode *elder=n>0?node1?node2;
n=abs(n);
while(shot!=elder)
{
if(n>0)
{
elder=elder->next;
n--;
}else{
shot=shot->next;
elder=elder->next;
}
}
return shot;
}
(2).当一链表有环一链表无环时 无相交
(3).当两链表都有环(入环节点为loop1,loop2)
1).当两链表在入环前相交,此时则为两链表都无环时的情况(将入环节点看作尾节链表在环前就相交点)
ListNode *Sameentrypoint(ListNode*node1,ListNode*node2,ListNode*loop)
{
ListNode *head1=node1;
ListNode *head2=node2;
int n=0;
while(node1!=loop)
{
node1=node1->next;
++n;
}
while(node2!=loop)
{
node2=node2->next;
--n;
}
ListNode *shot=n>0?head2:head1;
ListNode *elder=n>0?head1:head2;
n=abs(n);
while(shot!=elder)
{
if(n>0)
{
elder=elder->next;
n--;
}else{
shot=shot->next;
elder=elder->next;
}
}
return shot;
}
2)各自成环:loop1在向下走的过程中遇不上loop2,无相交
3)有不同的入环节点:loop1向下走的过程中遇上loop2,return(loop1或loop2)
ListNode*samering(ListNode *loop1,ListNode*loop2)
{
ListNode *loop=loop1;
loop1=loop1->next;
while(loop1!=loop)
{
if(loop1==loop2)return loop1;//return loop2;
loop1=loop1->next;
}
return nullptr;
}
双环情况下的判断函数
ListNode *Doublelooplist(ListNode*node1,ListNode*node2,ListNode*loop1,ListNode*loop2)
{
if(loop1==loop2)
return Sameentrypoint(node1,node2,loop1);
else return samering(loop1,loop2);
}
主代码
ListNode *Findingintersectingnodes(ListNode *node1,ListNode*node2)
{
ListNode*loop1=FindListIncorporate(node1);
ListNode*loop2=FindListIncorporate(node2);
if(loop1!=nullptr&&loop2!=nullptr)return Doublelooplist(node1,node2,loop1,loop2);
if(loop1==nullptr&&loop2==nullptr)return Ringlesslist(node1,node2);
return nullptr;
}