LeetCode刷题之no.141

关键知识

链表的处理

解题思路

一种简单的做法就是顺序遍历每个结点,然后每次都判断该点是否在前面遍历过的结点中,可以采用两层遍历的做法或者是采用set来存储前面的结点,然后每次在set中find这个结点。但是set会将空间复杂度大大增加。
另一种做法就是采用快慢两个指针在链表中遍历,如果快慢指针会相遇,则说明链表中存在环,否则不存在。存在环后,再通过一定的数学方法找到起始结点。该做法的时间复杂度为O(n),空间复杂度为O(1),为最佳做法。

简单做法

首先初始化一个set,然后遍历链表,不断地比较该节点是否出现过,出现过则说明存在环,没出现过就将此节点加进set,直到遍历完整个链表。
时间复杂度: 平均为O(n),最差为O(n^2)
空间复杂度: O(n)

最佳解法

采用两个指针分别为fast和slow,fast指针遍历的速度为slow的两倍,如果在fast到达链表结尾时两个指针不相遇,则说明链表不存在环,如果存在环,由于两者速度不一样,必定相遇,且相遇也说明了链表存在环。相遇之后,用meet指针记录相遇结点,然后用p指针指向起始结点head,然后两个指针同步遍历,直到两者相遇的结点即为环的起始结点。证明过程:
特殊例子
普遍证明

时间复杂度: O(n)
空间复杂度: O(1)

题目

Linked List Cycle II

简答做法

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        set<ListNode*> sl;
        ListNode* p = head;
        while (p) {
        	if (sl.find(p) == sl.end()) {
        		sl.insert(p);
        		p = p->next;
        	} else {
        		return p;
        	}
        }
        return nullptr;
    }
};

最优解法

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
    	ListNode *fast = head, *slow = head, *meet = nullptr;
    	if (!head) return nullptr;
    	fast = head->next ? head->next->next : head->next;
    	slow = head->next;
    	while (fast) {
    		if (fast == slow) {
    			meet = slow;
    			break;
    		}
    		fast = fast->next ? fast->next->next : fast->next;
    		slow = slow->next;
    	}
    	if (!meet) return nullptr;
    	ListNode* p = head;
    	while (p != meet) {
    		meet = meet->next;
    		p = p->next;
    	}
    	return meet;
    }
};

题目地址

Linked List Cycle II

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值