目录
一 . 关于 有环问题
如果 没环 最后肯定到 NULL 指针,有环 就会 死循环 无法找到 NULL 。
这题可以用快慢指针 来解决 也就是说他们 迟早会相遇 (为什么一定会相遇?可以推导出来)。
所以这题就是 追及 以及 相遇 的问题。
设他们相差 N 步,如果fast走 两 步,slow 走一步。
fast 每次 追一步 ,肯定可以追到。
如果 slow走1步 ,fast 走 3 步4 步 5 步..... 他们会相遇吗? 答案是会的!!!
我们用走三步来举例 ,也就是 fast 每次 追两步,设他们依然相差N步,那么就会有这样的表格:
当N为奇数时,每次追两步,他们就 追过头 了。
那我们继续设 圈大小为c 又要追c-1 步,c-1 如果是偶数,那么每次追两步就可以追上;
如果c-1是奇数,每次追两步,依旧会重复这个过程吗?
也就是存在结论: N 为奇数,C为偶数 那就一定追不上。(其实这个结论是不存在的)
4
偶数 != 偶数 - 奇数 , 所以之前结论不成立。
总结:也就是无论fast走2步以上,他们都会相遇!!!
我自己的题目的答案
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
if(head == NULL || head->next == NULL)
return false;
ListNode* slow = head;
ListNode* fast = head->next->next;
while(fast && fast->next)
{
if(fast == slow)
{
return true;
}
slow = slow->next;
fast = fast->next->next;
}
return false;
}
二. 返回 进环的 第一个节点
上题已经说明 无论fast走 多少步都会相遇。
这题其实也是推导公式,把他们相遇的点设为meet 从头开始数L就可以找到进环的节点
也就是说 L = C - N 因此只要 meet和头节点 同时一起走 就可以找到进环节点!!!
我的答案
typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head)
{
if(head == NULL || head->next == NULL)
{
return NULL;
}
ListNode* slow = head;
ListNode* fast = head;
ListNode* meet = NULL;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(fast == slow)
{
meet = slow;
break;
}
}
if(meet != NULL)//有meet才可以继续走噢
{
while(head != meet)
{
meet = meet->next;
head = head->next;
}
return meet;
}
else
return NULL;
}
三.随机链表的复制
他的意思就是重新复制一个一模一样的新链表。
如何做呢?其实有一种办法,先在它 中间遍历建立一个节点,遍历random节点,遍历切断节点。
第一步:遍历 建立新节点
第二步:遍历 把random链接
if(cur->random==NULL)
{
copy->random=NULL; //比如cur->random 为空
}
else
{
copy->random = cur->random->next; //如图所示
}
第三步: 遍历把 节点分开,再链接新节点
最后返回 head->next。
typedef struct Node Node;
struct Node* copyRandomList(struct Node* head) {
if(head==NULL)
return NULL;
Node* cur = head;
Node* copy = NULL;
//第一步 遍历中间节点
while(cur)
{
Node* copy = (Node*)malloc(sizeof(Node));
copy->val = cur->val;
copy->next = cur->next;
cur->next = copy;
cur = copy->next;
}
//第二步 遍历建立random节点(最困难)
cur = head;
while(cur)
{
copy = cur->next;
if(cur->random == NULL)
{
copy->random = NULL;
}
else{
copy->random = cur->random->next;
}
cur = copy->next;
}
//第三步 遍历把 新节点连接,断除旧节点,考验基础内容
cur = head;
while(cur)
{
copy = cur->next;
cur = copy->next;
if(cur)
copy->next = cur->next;
}
return head->next;
}