前言
我们将练习一做完,下来就开始有难度的了,只有过完这关,我们的知识才有更深的理解,大家加油。
OJ
练习
(1)相交链表
思路:如果相交,那么最后一个结点肯定相同,那么我们直接看最后一个结点相不相同,就能够判断他是否相交,然后我们再利用他们之间差的距离,我们让他们从同一起跑线出发,然后找到相交点。
代码如下
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* curA=headA;
struct ListNode* curB=headB;
int lenA=0;
int lenB=0;
//看A有多少个结点
while(curA->next)
{
lenA++;
curA=curA->next;
}
//看B有多少个结点
while(curB->next)
{
lenB++;
curB=curB->next;
}
//判断最后一个结点是不是相同的
//就能判断是不是相交。
if(curA!=curB)
{
return NULL;
}
int gas=abs(lenA-lenB);
struct ListNode* shoutList=headA;
struct ListNode* LongList=headB;
if(lenA>lenB)
{
shoutList=headB;
LongList=headA;
}
while(gas--)
{
LongList=LongList->next;
}
while(LongList!=shoutList)
{
LongList=LongList->next;
shoutList=shoutList->next;
}
return shoutList;
}
(2)环形链表<判断是否环>
思路:我们这道题考验的是逻辑结构,并不是我们写代码的能力,我们的数学思维,他是一个环,就是相当于一个循环链表,如果这时候我们利用速度指针,一个快指针和一个慢指针,快指针的速度是慢指针的二倍,我们等到了环中,快指针迟到会追上慢指针,所以等快指针等于慢指针的时候我们就认定这是个环。
-
现在思考一个问题(为什们速度是二倍,能不能是三倍或者是四倍?)
-
我们假设当fast进入环的时候,快慢指针之间的距离是N,所以当slow走一步的时候,fast走两步,所以他们之间的距离差一,那么他们迟早会追上。
但是当速度是三倍的时候,当fast进入环的时候,他们的距离差N,每走一步,距离就差N-2,所以如果在进入环后,差的距离是奇数,那么就永远追不上了。
bool hasCycle(struct ListNode *head) {
struct ListNode * slow=head;
struct ListNode * fast=head;
struct ListNode * cur=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(fast==slow)
{
return true;
}
}
return false;
}
(3)环形链表(判断环点的位置)
思路
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode * slow=head;
struct ListNode * fast=head;
struct ListNode * cur=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
{
while(cur!=slow)
{
cur=cur->next;
slow=slow->next;
}
return cur;
}
}
return NULL;
}
思路二:利用相交链表求解
思路,在快慢指针相遇,将其链表的下一个结点设为空指针,然后就变成了相交链表 ,下面画图解释。
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* curA=headA;
struct ListNode* curB=headB;
int lenA=0;
int lenB=0;
//看A有多少个结点
while(curA->next)
{
lenA++;
curA=curA->next;
}
//看B有多少个结点
while(curB->next)
{
lenB++;
curB=curB->next;
}
//判断最后一个结点是不是相同的
//就能判断是不是相交。
if(curA!=curB)
{
return NULL;
}
int gas=abs(lenA-lenB);
struct ListNode* shoutList=headA;
struct ListNode* LongList=headB;
if(lenA>lenB)
{
shoutList=headB;
LongList=headA;
}
while(gas--)
{
LongList=LongList->next;
}
while(LongList!=shoutList)
{
LongList=LongList->next;
shoutList=shoutList->next;
}
return shoutList;
}
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode * slow=head;
struct ListNode * fast=head;
struct ListNode * cur=NULL;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
{
//相交链表
cur=slow->next;
slow->next=NULL;
struct ListNode *ret =getIntersectionNode(head,cur);
return ret;
}
}
return NULL;
}
(4)复杂带随机指针的链表
思路:对于这个问题,思路还是很简单的,难的是我们代码的实现,就要考虑我们的基本功,
做法
- 1.拷贝链接结点在上面每个结点中间
2.设置链接结点的随机结点,并且它的随机结点于前一个结点的随机结点相同
3.最后将随机结点剪下来,然后再链接起来。
代码实现
struct Node* copyRandomList(struct Node* head) {
struct Node* cur=head;
//1.拷贝链接结点在上面每个结点中间
while(cur)
{
struct Node* next=cur->next;
struct Node* newnode=(struct Node*)malloc(sizeof(struct Node));
newnode->val=cur->val;
cur->next=newnode;
newnode->next=next;
cur=next;
}
cur=head;
while(cur)
{
struct Node* next=cur->next;
if(cur->random==NULL)
{
next->random=NULL;
}
else
{
next->random=cur->random->next;
}
cur=next->next;
}
//3.最后将随机结点剪下来,然后再链接起来。
cur=head;
struct Node* newhead=NULL;
struct Node* newcur=NULL;
while(cur)
{
struct Node* next=cur->next;
if(newhead==NULL)
{
newhead=newcur=next;
cur=next->next;
if(cur!=NULL)
next=cur->next;
}
else
{
newcur->next=next;
newcur=newcur->next;
cur=next->next;
if(cur!=NULL)
next=cur->next;
}
}
return newhead;
}
总结
还是要多练习,孰能生巧,一起加油