所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。
一、题目
二、哈希法
思路分析:这道题也可以用双指针法去解,这里我介绍一种哈希法。利用set集合的值不可重复的特性。首先我们定义一个集合链表指针s1,然后将链表中的每个指针依次放入集合当中,存在循环时就会第二次经过循环的首节点,终止循环然后记录这个节点即可。程序当中insert返回参数是一个对组,对组的第二个元素是bool类型,用来判断是否插入成功。
程序如下:
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
//思路:用哈希表记录走过的结点,当第二次走过某个结点,则为第一个入环的结点
set<ListNode*> s1;
ListNode* p = head;
s1.insert(p);
while (p != NULL)
{
p = p->next;
if (!s1.insert(p).second) {
return p;
}
}
return NULL;
}
};
复杂度分析:
- 时间复杂度: O ( n ) O(n) O(n),最坏情况需要遍历链表。
- 空间复杂度: O ( n ) O(n) O(n),最坏情况需要链表长度的空间。
三、完整代码
代码当中构建了一个链表类,写了一个利用数组生成链表ChainGenerator函数(不带循环,不带循环首节点)、链表打印LinkListPrint函数。循环链表CyCleChainGenerator函数参数为循环首节点和首节点位置。找到首节点位置然后插入,再让原来的链表尾节点指向这个循环首节点,循环就生成了。
# include <iostream>
# include <set>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode* next) : val(x), next(next) {}
};
// 链表类
class MyLinkedList {
public:
// 构造函数
MyLinkedList() {
_FakeNode = new ListNode(0, NULL); // 虚假头结点
_size = 0;
}
// 成员函数
void ChainGenerator(int arr[], int len);
void LinkListPrint(string str);
void CyCleChainGenerator(ListNode* CycleFirstNode, int CycleFirstNodeIndex);
// 成员变量
int _size;
ListNode* _FakeNode;
};
void MyLinkedList::ChainGenerator(int arr[], int len) {
if (_FakeNode->next != NULL) return;
ListNode* head = new ListNode(arr[0], NULL);
ListNode* p = head;
for (int i = 1; i < len; i++) {
ListNode* pNewNode = new ListNode(arr[i], NULL);
p->next = pNewNode; // 上一个节点指向这个新建立的节点
p = pNewNode; // p节点指向这个新的节点
}
_FakeNode->next = head;
_size = len;
}
void MyLinkedList::LinkListPrint(string str) {
cout << str << endl;
ListNode* cur = _FakeNode;
int index = _size;
while (index-- >0) {
cout << cur->next->val << ' ';
cur = cur->next;
}
cout << endl;
}
void MyLinkedList::CyCleChainGenerator(ListNode* CycleFirstNode, int CycleFirstNodeIndex) {
if (CycleFirstNodeIndex > _size) return;
if (CycleFirstNodeIndex < 0) CycleFirstNodeIndex = 0;
ListNode* cur = _FakeNode; // 虚结点
// 添加循环的第一个节点
// 需要断开上一一个阶段的链接,从插入位置的上一个索引开始处理
while (CycleFirstNodeIndex--) {
cur = cur->next;
}
CycleFirstNode->next = cur->next;
cur->next = CycleFirstNode;
// 找到尾节点,指向循环第一个节点
while (cur->next != NULL) {
cur = cur->next;
}
cur->next = CycleFirstNode;
_size++;
}
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
//思路:用哈希表记录走过的结点,当第二次走过某个结点,则为第一个入环的结点
set<ListNode*> s1;
ListNode* p = head;
s1.insert(p);
while (p != NULL)
{
p = p->next;
if (!s1.insert(p).second) {
return p;
}
}
return NULL;
}
};
int main()
{
int arr[] = { 2 };
int arr_len = sizeof(arr) / sizeof(int);
MyLinkedList m1;
m1.ChainGenerator(arr, arr_len);
ListNode* CycleFirstNode = new ListNode(1, NULL);
m1.CyCleChainGenerator(CycleFirstNode, 0);
m1.LinkListPrint("目标循环链表:");
Solution s1;
ListNode* result = s1.detectCycle(m1._FakeNode->next);
if (result != NULL) {
cout << "循环第一个节点:" << endl;
cout << "result->val: " << result->val << endl;
}
else {
cout << "NULL" << endl;
}
system("pause");
return 0;
}
end