算法通关村第一关-链表黄金挑战笔记|环的入口

解决链表环入口问题


文章目录

  • 解决链表环入口问题
  • 前言
    • 链表中环的问题
      • Hash和集合的解法:
      • 快慢指针实现解决:
    • 解题思路:
      • Hash或者使用集合的方式实现
      • 快慢指针(这里使用三次刚好解决)
  • 总结


前言

提示:无论今天过得如何,就当穿了一天的袜子,回家就脱了吧。

当然解决这个问题之前,我们需要了解一个概念,就是链表的有环是怎么判断的,定义是什么?
废话不多说,直接上图片💕

在这里插入图片描述
在这个A链表中,我们就看出他是存在环的

  1. 有环
  2. 节点 4 就是环的入口

这就引出来另一个问题了,怎么判断链表有环❔

链表中环的问题

当然拿到这个问题,思考的话(最快想到的解决方法就是Hash[map]),下来就是采用集合呗🥰,虽然这样的话可以很快解决,有点儿逃避链表的嫌疑😒

Hash和集合的解法:

遍历链表,一次将数据元素存入map中,是要是发现有相同的元素,就说明链表中有环,代码实现起来也很简单。

/**
 * 方法1:通过HashMap判断
 *
 * @param head
 * @return
 */
public static boolean hasCycleByMap(ListNode head) {
    // 一般条件下不改变head的位置
    ListNode pos = head;
    HashMap<ListNode,Integer> map = new HashMap();
    while(pos != null) {
        if(!map.containsKey(pos)){
            map.put(pos,null);
        }else{
            return true;
        }
        pos = pos.next;
    }
    return false;
}

使用集合的话,思想和上面👆类似,这里就不在重复了,直接上代码😂

/**
     * 方法1:通过HashSet判断
     *
     * @param head
     * @return
     */
    public static boolean hasCycleByMap(ListNode head) {
        // 保留一下头节点的位置
        ListNode pos = head;
        HashSet<ListNode> set = new HashSet<>();
        while (pos != null) {
        // if (set.contains(pos)){  // 这里也可以只用set判断
        //     return true;
        // }else{
        //      set.add(pos);
        // }
            if(!set.add(pos)){
                return true;
            }
            pos = pos.next;
        }
        return false;
    }

那么不逃离链表,就是使用链表需要怎么解决呢?思考(三分钟💡)
常见的算法解决 双指针 呗

快慢指针实现解决:

这里快慢指针要怎么理解呢?
我们类比一个场景:就是在一个圆形的操场上跑步,一个同学跑的快,一个同学跑的慢,经过一段时间后,必然会存在两人相遇的情况,况且正好是快的同学比慢的同学多跑一圈。
这里就可以建立数学模型

  1. 两位通过起始地点相同 快同学 v1 慢同学 v2(目前可以这样称呼 😂起名字很纠结ahhah)
  2. 经过相同的时间相遇 经过时间 t
  3. 假设围绕操场一圈的长度是 s
 s = (v1 -v2)t

这里放到链表里面就好办多了,我们就可以让fast走一步,然后fast和slow同时出发,如果后面出现fast和slow相遇,那就说明链表里面存在环呀🥰,这不就吧问题解决了。那我们就写一下代码吧。

/**
 * 方法2 通过双指针实现
 *
 * @param head
 * @return
 */

public static boolean hasCycleByTwoPoint(ListNode head) {
    // 校验参数
    if(head == null || head.next == null){ // 链表想要成环至少需要两个节点
        return false;
    }
    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;
}

解题思路:

Hash或者使用集合的方式实现

最简单的办法就是Hash呗,当然使用集合也不是不行(Set)。这就不在赘述了,显得就有点啰嗦啦🤣

快慢指针(这里使用三次刚好解决)

解决了链表有环的问题,我们再来看看怎么确定链表的环形入口在哪里❔(思考一下💡)
我们再来看这个环的图:
在这里插入图片描述
当然如果链表是这样的话也是一样的:

在这里插入图片描述

解决思路💕:

  1. 确定链表有环 (上面我们已经解决了)
  2. 确认链表的长度(这里可以相遇的时候 固定一个fast节点 让slow继续前行直到再次相遇 就可以得出环的长度 这里我们就简单的设置为 k )
  3. 确定环的入口(当我们从链表的后面往前看的话 链表环的入口刚好是倒数第 k 个节点。

有了思路那么实现起来就比较容易了🤩,下面就是代码的展示环节了😂

/**
 * 方法2 通过双指针实现
 *
 * @param head
 * @return
 */

public static ListNode detectCycleByTwoPoint(ListNode head) {
    // 校验参数
    if (head == null || head.next == null){ // 链表想要成环至少需要两个节点
        return null;
    }
    ListNode fast = head, slow = head;
    // 确定链表有环
    while(fast != null && fast.next != null){
        fast = fast.next.next;
        slow = slow.next;
        if (fast == slow){// 说明有环
            // 确认链表的长度
            int count = 1;
            slow = slow.next;
            while (fast != slow){
                count++;
                slow = slow.next;
            }
            // 确定环的入口
            fast = head;
            slow = head;
            int temp = count;
            while(temp >0){
                fast = fast.next;
                temp--;
            }
            while (count >0){
                fast = fast.next;
                slow = slow.next;
                count--;
            }
            return slow;
        }
    }
    return null;
}

总结

提示:链表环的问题是比较经典的问题,重点理解 链表环的入口问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/45935.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++笔记之使用普通指针和shared_ptr在堆上申请类对象的各种写法

C笔记之使用普通指针和shared_ptr在堆上申请类对象的各种写法 code review! 文章目录 C笔记之使用普通指针和shared_ptr在堆上申请类对象的各种写法1.几种不同的写法2.ChatGpt回答 1.几种不同的写法 注&#xff1a;使用普通指针申请堆内存&#xff0c;其实是应该有delete的&…

Redis常用数据类型和使用场景

Redis目前支持5种数据类型&#xff0c;分别是&#xff1a; String&#xff08;字符串&#xff09; List&#xff08;列表&#xff09; Hash&#xff08;字典&#xff09; Set&#xff08;集合&#xff09; Sorted Set&#xff08;有序集合&#xff09; 下面就分别介绍这五…

得物词分发平台技术架构建设与演进

前言 在文章开始前先介绍下导购&#xff0c;导购通常是指帮助消费者在购物过程中做出最佳决策的人或系统。在电商网站中&#xff0c;导购可以引导用户关注热卖商品或促销活动等&#xff0c;帮助用户更好地进行购物。导购的目的是为了提高用户的购物体验&#xff0c;促进销售额…

抽象工厂模式——产品族的创建

1、简介 1.1、简介 抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比&#xff0c;抽象工厂模式中的具体工厂不只是创建一种产品&#xff0c;它负责创建一族产品 1.2、定义 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff1a;提供…

4、非线性数据结构

上一节课我们讲了线性数据结构&#xff0c;这一节我们说下非线性数据结构。 非线性数据结构&#xff0c;从字面意思来看&#xff0c;就是指不是线性的结构。线性结构的特点是只有一个前驱和一个后继。 那么非线性结构的特点就是有多个前驱或后继了。 如果只存在一个没有前驱的…

Python爬虫基础

文章目录 Python学习记录Python基础爬虫&#xff1a;代码&#xff1a;运行结果&#xff1a; Python学习记录 Python基础爬虫&#xff1a; 代码&#xff1a; import urllib.request import random import chardet#请求头列表 us["Mozilla/4.0 (compatible; MSIE 6.0; Wi…

(学习笔记-IP)IP基础知识

基本认识 IP在TCP/IP参考模型中处于第三层&#xff0c;也就是网络层。 网络层的主要作用是&#xff1a;实现主机与主机之间的通信&#xff0c;也叫点对点的通信。 网络层与数据链路层的关系&#xff1a; MAC的作用是实现直连的两个设备之间通信&#xff0c;而IP负责没有直连的…

消息队列- 背景知识

这里写目录标题 前言消息队列消息队列的作用常见的消息队列消息队列的核心概念BrokerServer核心概念消息队列的核心API消息队列与消费者之间的工作模式交换机的类型消息队列的持久化 总结 前言 消息队列,不知道大家是否陌生,如果说消息队列感到陌生的话, 有一个模型肯定大家都…

Nginx下载和安装教程、Nginx目录结构、Nginx具体应用

1、Nginx概述 Nginx是一款轻量级的开源Web服务器软件&#xff0c;也是一种反向代理服务器。它以其高性能和灵活性而被广泛应用于互联网领域。本文将介绍Nginx的概述、下载和安装以及目录结构。 &#xff08;1&#xff09;Nginx介绍 Nginx最初由Igor Sysoev开发&#xff0c;目…

Pycharm工具Python开发自动添加注释(详细)

方法自动添加参数注释 定义了一个函数&#xff0c;在函数下面敲入了三个双引号后&#xff0c;enter回车并没有自动出现注释&#xff0c;如图&#xff1a; 解决办法 Pycharm中依次打开File —> Settings —> Tools —> Python Integrated Tools&#xff0c;如图&…

C++笔记之对指针类型的变量进行+1操作

C笔记之对指针类型的变量进行1操作 在C中&#xff0c;对指针类型的变量进行"1"操作会根据指针的数据类型而有所不同。这涉及到指针的算术运算&#xff0c;C中的指针算术运算是根据指针所指向的数据类型的大小来进行的。 code review! 文章目录 C笔记之对指针类型的…

最受欢迎的12个Python开源框架,还没用过你就OUT了!!!

今天给大家带来了12个在GitHub等开源网站中最受欢迎的Python开源框架。如果你正在学习python&#xff0c;那么这12个开源框架&#xff0c;千万别错过&#xff0c;这些框架包括事件I/O&#xff0c;OLAP&#xff0c;Web开发&#xff0c;高性能网络通信&#xff0c;测试&#xff0…

zookeeper-3.7.1集群

1.下载&解压安装包apache-zookeeper-3.7.1-bin.tar.gz 解压到/app/ &改名zookeeper-3.7.1 [rootnode1 app]# tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz -C /app/ [rootnode1 app]# mv apache-zookeeper-3.7.1-bin zookeeper-3.7.1 ---- 删除docs [rootnode1…

五步快速搭建个性化外卖小程序商城

随着人们生活节奏的加快&#xff0c;外卖行业蓬勃发展。为了满足用户的需求&#xff0c;许多企业开始使用小程序商城来提供外卖服务。那么&#xff0c;如何制作一个功能完善、用户友好的外卖小程序商城呢&#xff1f;下面就来为大家详细介绍一下制作的步骤。 首先&#xff0c;我…

Docker consul容器服务更新与发现

Docker consul容器服务更新与发现 一、什么事服务注册与发现二、什么是consul三、consul部署1、consul服务器2、registrator服务器3、consul-template 一、什么事服务注册与发现 服务注册与发现是微服务架构中不可或缺的重要组件。起初服务都是单节点的&#xff0c;不保障高可…

Vue3+Vite+TypeScript常用项目模块详解

目录 1.Vue3ViteTypeScript 概述 1.1 vue3 1.1.1 Vue3 概述 1.1.2 vue3的现状与发展趋势 1.2 Vite 1.2.1 现实问题 1.2 搭建vite项目 1.3 TypeScript 1.3.1 TypeScript 定义 1.3.2 TypeScript 基本数据类型 1.3.3 TypeScript语法简单介绍 2. 项目配置简单概述 2.…

【CEEMDAN-WOA-LSTM】完备集合经验模态分解-鲸鱼优化-长短时记忆神经网络研究(Python代码实现)

目录 &#x1f4a5;1 概述 1.1 完备集合经验模态分解原理 1.2 鲸鱼优化 1.3 LSTM &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Python代码实现 &#x1f4a5;1 概述 1.1 完备集合经验模态分解原理 早期的 EMD 方法具有较强的自适应性&#xff0c;能够有…

【弹力设计篇】聊聊限流设计

为什么需要限流 对于一个后端系统来说&#xff0c;其处理能力是有限的&#xff0c;会受到业务流程&#xff0c;系统配置等的限制&#xff0c;QPS和TPS有一个上限值&#xff0c;比如一个订单系统1分钟可以处理100个请求。当1分钟超过100个请求的时候&#xff0c;我们为了保证系…

5.python设计模式【单例模式】

内容&#xff1a;保证一个类只有一个实例&#xff0c;并提供一个访问它的全局访问点角色&#xff1a; 单例&#xff08;Singleton&#xff09; UML图 举个例子&#xff1a; 需求&#xff1a;一个类只能实例化一个对象&#xff0c;不能实例化多个对象 from abc import abstract…

QT【day2】

完善登录框&#xff1a; //main头文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include<QDebug> //信息调试类&#xff0c;用于打印输出 #include<QIcon> //图标头文件 #include<QPushButton> //按钮类头文件 #include…