练习一
题目:点击这里
1、思路:
我们可以看成一个数学问题:如果两个速度不同的人从同一起点开始跑步,路程相同,如果他们相遇了,这就说明这是一个环,如果不相遇,也并不代表就不是环了,假如,甲速度为x,乙速度为2x,当甲到了环的进口点时,乙早已经在环里面了,设乙到甲的距离为n,甲每走一步相当于乙走了两步,所以,甲每走一步,乙就更近甲一步,n逐步减一,直到n为0,则甲乙两人相遇,但是如果甲速度为x,乙速度为3x,当甲到了环的进口点时,乙已经在环里面了,设乙到甲的距离为n,甲每走一步,乙就更近甲两步,则n以逐步减二的趋势递减,如果n为偶数,则他们能相遇,如果n为奇数,乙则会跑到甲的前面一步,设这个环的周长为c,则乙到甲的距离为c-1,如果c-1是偶数,那么还是以减二的趋势递减,肯定会相遇,如果c-1是奇数,那么以减二的趋势递减,一定相遇不了,这里我们得出一个结论:速度相差一倍的两个人一定会相遇。
再回到这个题目中,我们可以创建两个指针,慢的指针一次走一步,快的指针走两步,这样,如果相遇则一定是环,否则快的指针一定会先走到NULL。
2、代码:
bool hasCycle(struct ListNode *head) {
struct ListNode* slow = head, *fast = head;
while(fast && fast->next)
{
slow = slow->next;//一次走一步
fast = fast->next->next;//一次走两步
if(slow == fast)
{
return true;
}
}
//走到这里就表示快指针已经走到NULL,表示不是环
return false;
}
练习二
题目:点击这里
1、思路
这个是练习一的升级版,其实,要想找到环的第一个节点,也就是环的进口点,只需要让甲再从起点出发,而乙从甲乙相遇点出发,再次相遇的点就是环的第一个节点,证明如下:
还是一样,设甲速度为n,乙速度为2n,环的周长为c,这次设环的第一个节点到相遇点的距离为n,直线的距离为l,则甲到相遇点走的路程是l+n,乙走的路程是l+k×c+n(其中k是圈数),时间相同,乙速度是甲的2倍,所以,2(l+n)=l+k×c+n,结果为l=k×c-n,得出,甲从起点出发,乙从相遇点出发,第一次相遇的点就是环的第一个节点。
2、代码
所以,和练习一一样,用快慢指针来走。
struct ListNode *hasCycle(struct ListNode *head) {
struct ListNode* slow = head, *fast = head;
//先判断是否为环
while(fast && fast->next)
{
//慢指针一次走一步,快指针一次走两步
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
return slow;
}
}
//如果跳出来了说明快指针已经走到尾了,表示不是环
return NULL;
}
struct ListNode *detectCycle(struct ListNode *head) {
//是环,则快指针从相遇点开始出发
struct ListNode* slow = head, *fast = head;
fast = hasCycle(head);
if(fast == NULL)
{
return NULL;
}
else
{
while(slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
}
练习三
题目:点击这里
1、思路
我们可以创建一个新链表,再用两个指针分别表示给出的这两个链表的头,用这两个指针指向的数据进行比较,小的那个放到新的链表中,再用小的那个指针指向下一个,再进行比较,小的那个再接在新链表的后面,以此类推,直到有一个指针指向空,表示这个指针已经遍历完了,再把没遍历完的接在新链表的后面,最后返回新的链表。
2、代码
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
if(list1 == NULL)
{
return list2;
}
if(list2 == NULL)
{
return list1;
}
//一个代表遍历,一个表示头指针
struct ListNode* newnode = NULL,*newnode_head = NULL;
//一个遍历list1,一个遍历list2
struct ListNode* list1_tail = list1,* list2_tail = list2;
//开始遍历list1,list2,直到有一个遍历完,结束遍历
while(list1_tail && list2_tail)
{
if(list1_tail->val < list2_tail->val)
{
if(newnode_head == NULL)
{
newnode_head = newnode = list1_tail;
}
else
{
newnode->next = list1_tail;
newnode = newnode->next;
}
list1_tail = list1_tail->next;
}
else
{
if(newnode_head == NULL)
{
newnode = newnode_head = list2_tail;
}
else
{
newnode->next = list2_tail;
newnode = newnode->next;
}
list2_tail = list2_tail->next;
}
}
//如果是list1先走完,就把剩下的list2接上
if(list1_tail == NULL)
{
newnode->next = list2_tail;
}
//如果是list2先走完,就把剩下的list1接上
if(list2_tail == NULL)
{
newnode->next = list1_tail;
}
return newnode_head;
}