Loading...
世界已冷酷至极, 让我们携手前行。
自助收录

判断“环形链表”中是否有环的两种解法

算法刷题2年前 (2023)更新 江南白衣
333 0 0
判断“环形链表”中是否有环的两种解法

环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。
注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。否则,返回 false 。
示例 1:

判断“环形链表”中是否有环的两种解法输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:

判断“环形链表”中是否有环的两种解法
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:

判断“环形链表”中是否有环的两种解法
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
解法一:哈希表
Set<ListNode> seen = new HashSet<>();
boolean add = seen.add(head);
seen.add(head)方法返回一个布尔值,如果Set中已存在元素,则再次添加会返回false
1、定义一个Set集合
2、遍历节点,若节点能添加到Set集合中,head指向下一个节点,若不能添加到Set集合中(说明集合中已经有该节点了),return true
解法二:双指针
链表的基础问题,链表的特点是每个节点只知道下一个节点,所以一个指针是无法判断链表中是否含有环。如果链表不含环,那么这个指针最终会遇到空指针null,表示链表到头了。判断单链表是否含环,经典解法就是双指针,一个跑得快,一个跑得慢。如果含有环,快指针最终会超慢指针一圈,和慢指针相遇,说明链表含有环。快指针步长为2,慢指针步长为1
1、定义两个指针,快指针fast,慢指针slow
2、遍历节点,让快节点每次前进两步,慢指针每次前进一步
3、如果含有环,快指针最终会超慢指针一圈,和慢指针相遇

package od;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 环形链表(2种解法)
 * 给你一个链表的头节点head, 判断链表中是否有环。
 * 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。
 * 注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
 * 如果链表中存在环 ,则返回 true 。否则,返回 false
 * 原文地址:https://www.codernav.com/2834.html
 * 更多算法详解:https://www.codernav.com
 */
public class OdTest28 {
    public static void main(String[] args) {
        // 定义链表
        ListNode node5 = new ListNode(5, null);
        ListNode node4 = new ListNode(4, node5);
        ListNode node3 = new ListNode(3, node4);
        ListNode node2 = new ListNode(2, node3);
        ListNode node1 = new ListNode(1, node2);
        // 定义环形链表,将node5指向node3
        node5.next = node3;
        // 哈希表
        boolean exist1 = f1(node1);
        System.out.println(exist1);
        // 双指针
        boolean exist2 = f2(node1);
        System.out.println(exist2);
        // ArrayList
        boolean exist = f(node1);
        System.out.println(exist);
    }

    public static boolean f(ListNode head) {
        List<ListNode> list = new ArrayList<>();
        while (head != null) {
            // 集合中已经存在node了,说明之前已经出现过了,该节点被指向两次
            if (list.contains(head)) {
                return true;
            }
            // 如果集合中没有,将当前节点存入集合
            list.add(head);
            // 当前节点指向下一个节点继续遍历
            head = head.next;
        }
        return false;
    }

    public static boolean f1(ListNode head) {
        Set<ListNode> seen = new HashSet<>();
        while (head != null) {
            // boolean add = seen.add(head);该方法返回一个布尔值,如果Set中已存在元素,则再次添加会返回false
            if (!seen.add(head)) {
                return true;
            }
            // 当前节点指向下一个节点继续遍历
            head = head.next;
        }
        return false;
    }

    public static boolean f2(ListNode head) {
        //初始化快慢指针指向头节点
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            //快指针每次前进两步
            fast = fast.next.next;
            //慢指针每次前进一步
            slow = slow.next;
            // 如果含有环,快指针最终会超慢指针一圈,和慢指针相遇
            if (fast == slow) {
                return true;
            }
        }
        return false;
    }

}


class ListNode {
    int val;
    ListNode next;

    ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
}

 

© 版权声明

相关文章

开发者导航新手教程

暂无评论

暂无评论...