专栏首页小浩算法《剑指offer》第22天:链表成环的新解法

《剑指offer》第22天:链表成环的新解法

今天为大家带来,链表检测成环的经典题目。如果你觉得你会了,请你不妨耐心些认真看下去,我相信会有一些不一样的收获!还是先从一道题目开始哟,准备好了吗?Let' s go !

01、题目分析

第141题:环形链表

给定一个链表,判断链表中是否有环。为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

题目可能你会觉得过于简单!但是不妨耐心看完! 则一定会有收获!

02、题目分析

题解一:哈希表判定

思路:通过hash表来检测节点之前是否被访问过,来判断链表是否成环。这是最容易想到的一种题解了。过于简单,直接上代码,go:

func hasCycle(head *ListNode) bool {
    m := make(map[*ListNode]int)
    for head != nil {
        if _,exist := m[head];exist {
            return true
        }
        m[head]= 1
        head = head.Next
    }
    return false
}

java:

public boolean hasCycle(ListNode head) {
    Set<ListNode> set = new LinkedHashSet<>();
    while (head != null) {
        if (set.contains(head)) {
            return true;
        }
        set.add(head);
        head = head.next;
    }
    return false;
}

题解二:JS特殊解法

相信对于 JS 中的 JSON.stringify() 方法大家都用过,主要用于将 JS 对象 转换为 JSON 字符串。基本使用如下:

var car = { 
  name: '小喵', 
  age: 20, 
} 
var str = JSON.stringify(car);
console.log(str) 
//=> {"name":"小喵","age":20}

大家想一下,如果是自己实现这样的一个函数,我们需要处理什么样的特殊情况?对,就是循环引用。因为对于循环引用,我们很难通过 JSON 的结构将其进行展示!比如下面:

 var a = {} 
 var b = { 
   a: a 
 }
 a.b = b
 console.log(JSON.stringify(a))
 //=> TypeError: Converting circular structure to JSON

那我们思考,对于环形链表,是不是就是一个循环结构呢?当然是!因为只要是环形链表,它一定存在类似以下代码:

a.Next = bb.Next = a

所以我们可以通过 JSON.stringify() 的特性进行求解:

var hasCycle = function(head) {
    try{
        JSON.stringify(head)
    }catch(e){
        return true
    }
    return false
};

当然,这种解法并不是建议的标准题解!在此列出是为了拓宽思维!(大家如有兴趣,可以自己去看下JSON.stringify 内部的实现,是如何检测循环引用的。)

题解三:双指针解法

本题标准解法!常识内容,必须掌握

思路来源:先想象一下,两名运动员以不同速度在跑道上进行跑步会怎么样?相遇!好了,这道题你会了。

解题方法:通过使用具有 不同速度 的快、慢两个指针遍历链表,空间复杂度可以被降低至 O(1)。慢指针每次移动一步,而快指针每次移动两步

假设链表为

其步骤如下:

分析完毕,直接上代码, go:

func hasCycle(head *ListNode) bool {  
    if head == nil {
        return false
    }
    fast := head.Next       // 快指针,每次走两步
    for fast != nil && head != nil && fast.Next != nil {
        if fast == head {   // 快慢指针相遇,表示有环
            return true
        }
        fast = fast.Next.Next  
        head = head.Next        // 慢指针,每次走一步
    }
    return false
}

java:

public boolean hasCycle(ListNode head) {
    if (head == null) return false;

    ListNode fast = head.next;

    while (fast != null && head != null && fast.next != null) {
        if (fast == head) {   // 快慢指针相遇,表示有环
            return true;
        }
        fast = fast.next.next;
        head = head.next;
    }

    return false;
}

这里我们要特别说明一下,为什么慢指针的步长设置为 1 ,而快指针步长设置为 2 。

首先,慢指针步长为 1,很容易理解,因为我们需要让慢指针步行至每一个元素。而快指针步长为 2 ,通俗点可以理解为他们的相对速度只差 1,快的只能一个一个格子的去追慢的,必然在一个格子相遇。

如果没看懂,我们来分析:在快的快追上慢的时,他们之间一定是只差 1 个或者 2 个格子。如果落后 1 个,那么下一次就追上了。如果落后 2 个,那么下一次就落后 1 个,再下一次就能追上!如下图:

所以我们的快指针的步长可以设置为 2 。

03、特别说明

我们常会遇到一些所谓的“简单题目“,然后用着前人留下来的那些”经典题解“迅速作答。在解题的过程中,追求公式化、模板化。当然,这个过程是好的,因为社会、工作、学业要求我们如此!但是,我希望我们也可以留下一些自己的思考,纵然不是最优解,但是是我们自己想到的、创造的!真正在算法题中去收获快乐~

本文分享自微信公众号 - 小浩算法(xuesuanfa),作者:程序员小浩

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-09-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 漫画:不一样的链表成环检测!

    今天为大家带来,链表检测成环的经典题目。如果你觉得你会了,请你不妨耐心些认真看下去,我相信会有一些不一样的收获!

    程序员小浩
  • 面试超级爱问的全排列!!!

    假如我们不是做算法题,而是做数学题。我们会一个位置一个位置的来考虑,先写出以1开头的排列,再写出以2开头的排列,最后写出以3开头的排列。

    程序员小浩
  • 漫画:排序算法系列 第一讲(利用插入算法思想解题)

    在leetcode中,直接搜索排序标签出现的题目有80余道,这是与排序直接相关的题目,不包括其他一些用到排序思想的题目。

    程序员小浩
  • 链表中间段逆序

    LeetCode 92. Reverse Linked List II 已知链表头节点指针head,将链表从位置m到n逆序。(不申请额外空间)

    小飞侠xp
  • LeetCode 61. Rotate List

    ShenduCC
  • python算法与数据结构-栈(43)

      栈作为一种数据结构,是一种只能在一端进行插入和删除操作。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹...

    Se7eN_HOU
  • Golang Leetcode 203. Remove Linked List Elements.go

    版权声明:原创勿转 https://blog.csdn.net/anakinsun/article/details/89012730

    anakinsun
  • 基于栈和队列实现括号匹配算法

    视频 http://study.163.com/course/courseLearn.htm?courseId=555010#/learn/video?l...

    陈黎栋
  • 3224: Tyvj 1728 普通平衡树

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 2566  Sol...

    HansBug
  • 35. 翻转链表

    样例 给出一个链表1->2->3->null,这个翻转后的链表为3->2->1->null

    和蔼的zhxing

扫码关注云+社区

领取腾讯云代金券