六月十五号Leetcode
1、找公共节点
延伸问题:
1、为什么一定会相遇?不会追不上吗?
假设slow进环时,fast与slow之间的距离是N,两者之间的距离每次运动缩小一,一定会出现N = 0 的情况,所以一定会相遇
2、那么可以fast指针一次走三步吗?四步可以吗?n步呢?
令slow进环时,两者之间的距离为N, 链表的环的大小是C,在进环以前链表的长度是L。
对于走两步而言,两者之间的相对速度是二,这时候进行分类讨论,若链表的环的大小是偶数,则会陷入死循环,最后走完每一轮fast都比slow快一步;
但实际上分析,死循环的条件是N为奇数,C为偶数。
当slow刚好进环时,设fast在这里已经走了x圈,fast指针在这里走的路程是:L + x * C + C - N;slow指针在这里走的路程是L;两者存在关系:3*L = L + x * C + C - N;即2*L =(x+1)*C -N;
但是若C为奇数而N为偶数,则上式一定不成立,所以一定能够相遇
至于其他走法都是同一种思路,走几步没关系,关键的是他们之间的速度差,不过越往后需要分类讨论的情况越复杂
3、给定一个链表,请判断他是否有环,若有环,则返回环的起始节点,若没有环,则返回NULL;
链表以前的大小是L,环的大小是C,slow入环时两者之间的距离是N;
slow走的路程一定是小于C的,因为slow每走一步,两者之间的距离都小一,而两者间最大距离最大就是C(不等于),所以slow只走环的一部分就追上了
设slow到达环时,fast一走x圈。
相遇时:slow:L+N;fast:L+x*C+N
故2*(L+N)= L+x*C+N 即L=x*C-N
这里可以理解为先让我们的meet指针回到我们的环的起点位置(-N),此后再让他走x圈(+x*C),在某次他走完一圈以后,从head开始的cur指针就也到达了环的起点,而这时meet也在起点,两者相遇。
具体代码实现如下:
typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
ListNode* meet = NULL;
ListNode* cur = head;
int flag = 0;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
{
meet = fast;
flag = 1;
break;
}//这里要先进行判断
}
if(flag == 0)
{
return NULL;
}
else
{
while(cur != meet)
{
cur = cur->next;
meet = meet->next;
}
return cur;
}
}
或者也可以让meet->next = Newhead, 再将meet->next置为空,从而转化为求公共节点问题
找公共节点如下····························
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
//还是要用快慢指针解决
//当快指针进环的时候,慢指针还在中间,slow进环以后,开始追击
//若不带环,fast就走到头了
//而若带环,因为有速度差,所以fast最终一定能找slow
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
{
return true;
}
}
return false;
}
2、深拷贝
typedef struct Node Node;
struct Node* copyRandomList(struct Node* head) {
//第一步,将用于复制的节点都插在对应节点的后面
Node* cur = head;
while(cur)
{
Node* copy = (Node*)malloc(sizeof(Node));
copy->val = cur->val;
copy->next = copy->random = NULL;
copy->next = cur->next;
cur->next = copy;
cur = copy->next;
}
//第二步,处理copy节点的random指针
cur = head;
while(cur)
{
Node* copy = cur->next;
if(cur->random == NULL)
{
copy->random = NULL;
}
else
{
copy->random = cur->random->next;
}
cur = copy->next;
}
//恢复原链表,以及返回新链表
cur = head;
Node* newhead, *newtail;
newhead = newtail = NULL;
while(cur)
{
Node* copy = cur->next;
Node* next = copy->next;
if(newhead == NULL)
{
newhead = newtail = copy;
}
else
{
newtail->next = copy;
newtail = newtail->next;
}
cur->next = next;
cur = next;
}
return newhead;
}