您的位置:首页 > 职场人生

面试OR笔试30——单链表环入口节点

2017-09-04 10:37 330 查看

1 题目及要求

1.1 题目描述

找出一个有环的单链表的入口节点,若没有环则输出空。

 

2 解答

2.1 题目分析

1、可以用两个指针来解决。先定义两个指针p1, p2连个指向链表头节点。如果链表中的环有c个节点,则指针p2在链表上向前移动n步,然后两个指针再以相同的速度移动。当p1指向环入口节点时p2已经绕着环走了一圈后又回到了环入口节点。所以解题思路如下:

1)先求环内的任意一个节点;

2)求环的长度;

3)求入口节点。

 

2、设置两个指针slow和fast,分别每次向前走一步和走两步。若有环则必会相遇,且相遇时slow肯定没有遍历完链表,而是停在环内的某一节点,而fast已经在环内走了k1圈了(1<=k1)。假设链表非环的部分长为n,环部分长为c,环入口到相遇节点的距离为d。于是有,slow走的距离为n+d,fast走的距离为n+d+k1*c。由于fast是slow速度的两倍因此有

2*(n+d) = n+d+k1*c     ==>  n+d = k1*c       ==>   n = (k1-1)*c + (c-d)

c-d为相遇节点到环入口节点的距离,由此可见,从链表头到环入口节点的距离等于k1-1圈内环长度+相遇几点到环入口的距离。于是我们可以让两个指针分别从头结点和相遇节点相同速度同时出发向前走,则必会在环入口相遇。

 

2.2 代码

#include <iostream>
using namespace std;

// 链表节点类
struct ListNode{
int val;
ListNode *next;
ListNode(int x = 0):val(x),next(nullptr){}
};

ListNode* getCycleNode(ListNode* l1){
ListNode *np(l1);
while(np && np->next){
l1 = l1->next;
np = np->next->next;
if(l1==np)return l1;
}
return nullptr;
}

int cycleLength(ListNode* l1){
l1 = getCycleNode(l1);
if(!l1) return 0;
ListNode *np(l1->next);
int res(1);
while(np!=l1) {
++res;
np = np->next;
}
return res;
}

ListNode* getEnterNode1(ListNode* l1){
ListNode *np(l1);
int k1 = cycleLength(l1);
if(k1<1)return nullptr;
for(;0<k1;--k1)
np = np->next;
while(l1!=np){
l1=l1->next;
np=np->next;
}
return l1;
}

ListNode* getEnterNode(ListNode* l1){
ListNode *slow(l1), *fast(l1);
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
if(slow==fast) {
while(l1!=slow){
l1=l1->next;
slow=slow->next;
}
return l1;
}
}
return nullptr;
}

int main(){
ListNode ht[7]={1,2,3,4,5,6,7};
for(int k1(0);k1<6;++k1)ht[k1].next = ht+k1+1;

ListNode *np1(nullptr),*np2(nullptr);
cout << ">>>>>>>空链表:" << endl;
cout << "链表内环长度 : " << cycleLength(ht) << endl;
np1 = getEnterNode1(nullptr);
np2 = getEnterNode(nullptr);
cout << "链表环入口节点1: ";
np1 ? (cout << np1->val):(cout << "NULL"); cout << endl;
cout << "链表环入口节点2: ";
np2 ? (cout << np2->val):(cout << "NULL"); cout << endl;

cout << endl << ">>>>>>>无环链表:" << endl;
cout << "链表内环长度 : " << cycleLength(ht) << endl;
np1 = getEnterNode1(ht);
np2 = getEnterNode(ht);
cout << "链表环入口节点1: ";
np1 ? (cout << np1->val):(cout << "NULL"); cout << endl;
cout << "链表环入口节点2: ";
np2 ? (cout << np2->val):(cout << "NULL"); cout << endl;
for(int k1(6);-1<k1;--k1){
ht[6].next = ht+k1;
cout << endl << ">>>>>>>" << (7-k1) << "环链表:" << endl;
cout << "链表内环长度 : " << cycleLength(ht) << endl;
np1 = getEnterNode1(ht);
np2 = getEnterNode(ht);
cout << "链表环入口节点1: ";
np1 ? (cout << np1->val):(cout << "NULL"); cout << endl;
cout << "链表环入口节点2: ";
np2 ? (cout << np2->val):(cout << "NULL"); cout << endl;
}
return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 面试 笔试 C++ 链表