141. 环形链表|刷题打卡

159 阅读2分钟

一、题目描述

二、解题思路

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 * 链表,双指针的题
 * 题目的意思是什么?关键点是如何判断是有环
 * 尾结点指向到了之前有的节点,需要对每一次的节点进行判断,是否已经存在过了。
 * 那么这时候怎么区分这个节点就是原节点,而不是一个新的节点呢?通过内存地址来判断吗?
 * 之思考的上面,下面是看题解写的
 * 可以通过存储的内存地址来判断,通过 Map 来存储
 * 击败了19.21%的用户
 * 击败了5.00%的用户
 */
// var hasCycle = function(head) {
//     let map = new Map();
//     // 第一次错误,没有考虑到空链表的情况,[] -1,返回了undefined;
//     if(!head) return false;
//     while(head){
//         if (map.has(head)) return true;
//         map.set(head);
//         head = head.next;
//         if (head === null) return false;
//     }
// };
/**
 * 方案二,双指针方法,思想,两个人比赛赛跑,如果赛道是环形的,那么跑得快的一定会追上跑的慢的。
 * 实现思路:构建两个指针,一个快,一个慢。当快的和慢的相等了,表示追上了。
 * 追上的前提是,他们的距离在不断的拉大,相对距离不能一直保持一样,所以慢的每次跑一步,
 * 快的每次跑两步,这样下去总能追上。
 * 104 ms, 在所有 JavaScript 提交中击败了25.33%的用户
 * 内存消耗:40.3 MB, 在所有 JavaScript 提交中击败了38.08%的用户
 */

var hasCycle = function(head) {
    // 边缘情况考虑
    if (!head || !head.next) return false;
    let flow = head;
    let fast = head.next;
    while (fast !== null && fast.next) {// 判断走的快的是否已经到达了终点
        if (flow === fast) return true;
        flow = flow.next;
        fast = fast.next.next;
        if (fast === flow) {
            return true;
        }
    }

    return false;
}

总结:

两种方法,一种是通过哈希表进行存储,判断节点是否存在。 第二种方法,双指针,两个人在一个赛道上面跑步,如果赛道是环形赛道,跑得快的一定会追上跑得慢的。如果不是,跑的快的则会先到达终点。