leetcode_141和leetcode_142解题思路

题意:判断一个链表是否含有环,且返回成环的起始节点。要求空间复杂度为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;
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值