leetcode — linked-list-cycle-ii

本文介绍了一种使用双指针法高效找出链表循环起始节点的方法,通过慢快指针首次相遇后重新定位慢指针至头部,两者再次同步移动直至第二次相遇,即为循环起点。
/**
 * Source : https://oj.leetcode.com/problems/linked-list-cycle-ii/
 *
 * Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
 *
 * Follow up:
 * Can you solve it without using extra space?
 */
public class LinkedListCycle2 {

    /**
     * 如果链表是循环的,则找到循环的开始节点
     * 否则,返回null
     *
     * 依然使用双指针法,如果是循环链表的话,
     * slow和fast第一次相遇之后,将slow = head,
     * 然后将slow和fast每次移动一个节点,第二次相遇的时候就是循环的起始节点
     *
     * 原理:
     * 假设head到start的距离a,slow和fast第一次相遇的位置距离start为b,循环链表周长为c,第一次相遇的时候fast走过的长度一定是slow的两倍,在过程中遍历了循环链表n次
     * (a + b) * 2 = a + n * c + b
     * 那么a = n*c - b => a + b = n*c
     * 也就是说,现在让两个指针slow指向head,fast指向第一次相遇的位置,然后每次两个指针移动一个节点,直到下一次相遇,正好走过n个周长,即下一次相遇在start位置
     *
     * @param head
     * @return
     */
    public LinkedNode findCycleStart (LinkedNode head) {
        if (head == null) {
            return null;
        }
        LinkedNode slow = head;
        LinkedNode fast = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                break;
            }
        }
        if (fast == slow) {
            // 链表存在循环
            slow = head;
            while (slow != fast) {
                slow = slow.next;
                fast = fast.next;
            }
            return slow;
        }
        return null;
    }

    private class LinkedNode {
        int value;
        LinkedNode next;

    }

    /**
     * 创建普通的链表
     * @param arr
     * @return
     */
    public LinkedNode createList (int[] arr) {
        if (arr.length == 0) {
            return null;
        }
        LinkedNode head = new LinkedNode();
        head.value = arr[0];
        LinkedNode pointer = head;
        for (int i = 1; i < arr.length; i++) {
            LinkedNode node = new LinkedNode();
            node.value = arr[i];
            pointer.next = node;
            pointer = pointer.next;
        }
        return head;
    }

    /**
     * 将链表变为循环链表,循环起始为第index个node
     * @param head
     * @param index
     */
    public void makeCycle (LinkedNode head, int index) {
        if (head == null) {
            return;
        }
        LinkedNode tail = head;
        int count = 1;
        while (tail.next != null) {
            tail = tail.next;
            count++;
        }
        LinkedNode p = head;
        if (index > count) {
            index = index % count;
        } else if (index < 0) {
            index = Math.abs(index);
        }
        while (p != null) {
            index--;
            if (index < 1) {
                tail.next = p;
                break;
            }
            p = p.next;
        }

    }

    public static void main(String[] args) {
        LinkedListCycle2 linkedListCycle = new LinkedListCycle2();
        LinkedNode list = linkedListCycle.createList(new int[]{1,2,3,4,5});

        System.out.println(linkedListCycle.findCycleStart(list) + " == null");

        linkedListCycle.makeCycle(list, 2);
        System.out.println(linkedListCycle.findCycleStart(list).value + " == 2");
    }
}
标题基于SpringBoot的马术俱乐部管理系统设计与实现AI更换标题第1章引言介绍马术俱乐部管理系统的研究背景、意义、国内外研究现状、论文方法及创新点。1.1研究背景与意义阐述马术俱乐部管理系统对提升俱乐部管理效率的重要性。1.2国内外研究现状分析国内外马术俱乐部管理系统的发展现状及存在的问题。1.3研究方法以及创新点概述本文采用的研究方法,包括SpringBoot框架的应用,以及系统的创新点。第2章相关理论总结和评述与马术俱乐部管理系统相关的现有理论。2.1SpringBoot框架理论介绍SpringBoot框架的基本原理、特点及其在Web开发中的应用。2.2数据库设计理论阐述数据库设计的基本原则、方法以及在管理系统中的应用。2.3马术俱乐部管理理论概述马术俱乐部管理的基本理论,包括会员管理、课程安排等。第3章系统设计详细描述马术俱乐部管理系统的设计方案,包括架构设计、功能模块设计等。3.1系统架构设计给出系统的整体架构,包括前端、后端和数据库的交互方式。3.2功能模块设计详细介绍系统的各个功能模块,如会员管理、课程管理、预约管理等。3.3数据库设计阐述数据库的设计方案,包括表结构、字段设计以及数据关系。第4章系统实现介绍马术俱乐部管理系统的实现过程,包括开发环境、编码实现等。4.1开发环境搭建介绍系统开发所需的环境,包括操作系统、开发工具等。4.2编码实现详细介绍系统各个功能模块的编码实现过程。4.3系统测试与调试阐述系统的测试方法、测试用例以及调试过程。第5章系统应用与分析呈现马术俱乐部管理系统的应用效果,并进行性能分析。5.1系统应用情况介绍系统在马术俱乐部中的实际应用情况。5.2系统性能分析从响应时间、并发处理能力等方面对系统性能进行分析。5.3用户反馈与改进收集用户反馈,提出系统改进建议。第6章结论与展望总结马术俱乐部管理系统的设计与实现成果,并展望未来的研究
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值