令人头秃的LeetCode——141. 环形链表

题目链接:141. 环形链表


解法一 暴力法(哈希表)

思路

  • 遍历链表,利用哈希表存储指针指向节点的地址。
  • 判断指针指向节点的地址是否在哈希表中存在,若存在,直接返回true,否则,指针向后移动,继续遍历。
  • 若指针指向空,返回false。
	public boolean hasCycle(ListNode head) {
        ListNode cur = head;
        HashSet<ListNode> set = new HashSet<>();
        while (!set.contains(cur) && cur != null){
            set.add(cur);
            cur = cur.next;
        }
        return cur != null;
    }

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(n),建立了哈希表,开辟了额外空间

解法二 双指针(快慢指针)

思路

快慢指针,可以理解为两个速度不一样的运动员在沿着环形跑道追赶。

假设跑道长度为 N N N ,运动员A的速度为 x x x ,运动员B的速度为 y y y ,运动员B起点比运动员A靠前 k k k 个单位长度,两者同时出发,最终能够相遇吗?答案是肯定的,只需要满足等式 y T = x T + N − k yT = xT + N - k yT=xT+Nk,式子表示 T T T 时刻两者相遇。

具体的,我们令 x = 1 , y = 2 x = 1, y = 2 x=1y=2,代入上式,可求得相遇时间 T = N − k T = N - k T=Nk

  • 初始化双指针,并定义起点位置,快慢指针的速度分别为2和1。
  • 若链表中存在环,则两指针必定相遇,若不存在,则需要注意快指针是否已经指向空。
	public boolean hasCycle(ListNode head) {
        if (head == null)
            return false;
        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast){
            if (fast == null || fast.next == null)
                return false;
            fast = fast.next.next;
            slow = slow.next;
        }
        return true;
    }

复杂度分析

  • 时间复杂度:
    • 若链表不存在环,时间复杂度为O(n)
    • 若链表存在环,环的长度为N,非环部分为M,则在非环部分首先迭代了M次。接着,进入环部分,假设此时快指针领先k个单位长度,k的取值范围为[0, N],则进行(N - k)次迭代,一共迭代(M + N - K)次,时间复杂度为O(M + N - K),即为O(n)
    • 综上,时间复杂度为O(n)
  • 空间复杂度:O(1)

小结

对付链表,直观的三个思路:

  • 单指针(暴力法,直观,但浪费点空间)
  • 双指针(省空间,思路略复杂,骚操作比较多)
  • 递归(毕竟链表结构是递归的,Emmmm~但是难想)
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页