题意:判断一个链表是否含有环,且返回成环的起始节点。要求空间复杂度为o(1)或者o(0)。
解题思路:一:首先想到的是用vector辅助变量记录遍历过的节点,当访问已遍历的节点时,则认为有环;
二:设置一个flag值,将每个节点的value值都遍历设置为flag,当出现第一个value值是flag时,说明有环(该方法有两个缺陷:1.修改了原列表中的value值;2.存在很小概率的情况原列表中value值本来就是flag,这种情况该方法就会出错;
三、想在方法二的基础上将每个节点的value值设置成节点的地址,但实现过程发现把指针类型强制转换成int类型会报错,所以该方法暂时还没想到解决方案;
四、从网友答案上看到一个超经典的方法:快慢指针和先后指针,用到了初中学习的很高级的追及问题,相当有趣。
#include<iostream>
#include<vector>
using namespace std;
// Definition for singly-linked list.
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
//方法一:用vector变量的方法,默认空间复杂度为o(1);
class Solution {
public:
bool hasCycle(ListNode *head) {
bool result = false;
if (!head) return result;
vector<ListNode*> visited;
while (head)
{
if (find(visited.begin(), visited.end(), head) != visited.end())
{
result = true;
break;
}
else
{
visited.push_back(head);
head = head->next;
}
}
return result;
}
};
//方法三:宏定义一个-infinite flag标志位(假设原有节点的val值不可能取值到这个标志位)
#define inf -1000000
class Solution {
public:
bool hasCycle(ListNode *head) {
bool result = false;
if (!head) return result;
while (head)
{
if (inf == head->val)
{
result = true;
break;
}
else
{
head->val = inf;
head = head->next;
}
}
return result;
}
};
上一个方法的改进:宏定义一个-infinite flag标志位(假设原有节点的val值不可能取值到这个标志位),且不要result辅助变量,空间复杂度为o(0)
#define inf -1000000
class Solution {
public:
bool hasCycle(ListNode *head) {
//bool result = false;
if (!head) return false;
while (head)
{
if (inf == head->val)
{
goto out;
}
else
{
head->val = inf;
head = head->next;
}
}
return false;
out:
return true;
}
};
//方法三:将每个节点的value值都改成节点对应的逻辑地址(即将指向该节点的指针变量强制转化成int),(目前这个方法还有点问题,指针变量转换成int有误)
//存取变量的逻辑地址在32位地址总线的系统里都是占4个字节的,这里就不用用到辅助变量了
//且没有visited数组遍历的过程,时间复杂度和空间复杂度都很低
class Solution {
public:
bool hasCycle(ListNode *head) {
bool result = false;
if (!head) return result;
while (head)
{
if (int(head) == head->val) //报错
{
result = true;
break;
}
else
{
head->val = int(head);
head = head->next; //报错
}
}
return result;
}
};
//leetcode_142题和leetcode_141几乎一样,解答如下
#define inf -1000000
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
//bool result = false;
if (!head) return nullptr;
while (head)
{
if (inf == head->val)
{
goto out;
}
else
{
head->val = inf;
head = head->next;
}
}
return nullptr;
out:
return head;
}
};
//leetcode_142方法二:网友方法,快慢指针和先后指针,虽然用了指针变量,但是思维上很高级,很有借鉴意义
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if (!head || !head->next) return nullptr;
ListNode* fast=head; //快指针
ListNode* slow=head; //慢指针,同时也是先指针
ListNode* entry=head; //后指针
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (slow == fast)
{
while (entry != slow)
{
entry = entry->next;
slow = slow->next;
}
return slow;
}
}
return nullptr;
}
};