LeetCode 热题 100_环形链表 II(26_142_中等_C++)(单链表;哈希表;快慢指针)

LeetCode 热题 100_环形链表 II(26_142)

    • 题目描述:
    • 输入输出样例:
    • 题解:
      • 解题思路:
        • 代码实现(思路一(哈希表)):
        • 代码实现(思路二(快慢指针)):

题目描述:

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

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

不允许修改 链表。

输入输出样例:

示例 1:
请添加图片描述

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

示例 2:
请添加图片描述

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

示例 3:
请添加图片描述

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

提示:
链表中节点的数目范围在范围 [0, 104] 内
-105 <= Node.val <= 105
pos 的值为 -1 或者链表中的一个有效索引

题解:

解题思路:

思路一(哈希表)
1、创建一个哈希集合用于存储遍历过的链表结点,如果当前遍历的结点不在哈希集合中则存入集合,如果当前遍历的结点存在哈希集合中则为链表开始入环的第一个节点,返回该结点程序结束。

2、复杂度分析:
① 时间复杂度:O(N),其中 N 为链表中节点的数目。我们恰好需要访问链表中的每一个节点。
② 空间复杂度:O(N),其中 N 为链表中节点的数目。我们需要将链表中的每个节点都保存在哈希表当中。

思路二(快慢指针):
1、通过题目分析,我们需要找到链表开始入环的第一个节点,通过分析我们可以得出下图(a代表环状链表之前的节点数,b代表环装链表的节点数):
请添加图片描述
fast=2slow(每次fast走两步,slow走一步)
fast=slow+n
b (b代表环中结点的个数,nb代表slow==fast时,fast比slow多在环中转了多少圈)
两式联立可得fast=2n
b,slow=n*b。

如果我们从头开始遍历结点到环的入口结点需要走:a+mb步。m取值为(0,1,2,…)
我们发现 slow=n
b 再走 a 步,也就是 a+n*b正好满足到达入口结点的条件。
我们这里的a的大小不知道怎么办,我们发现从首结点开始到入口正好为a步,所以我们从head和slow(fast==slow时)同时移动则会在环形入口处相遇。

2、具体思路如下:
① 定义两个指针,fast和slow,fast每次走两步,slow每次走一步。
② 通过遍历找到找到环中slow==fast的点(如果fast遍历到nullptr则不存在环,也就不存在环的入口结点)
③ 然后再令fast指向首结点,将fast和slow同时进行移动,这时fast每次移动一步,直到slow ==fast此时指向的结点为环的入口结点。

3、复杂度分析
① 时间复杂度:O(N),第二次相遇中,慢指针须走步数 a<a+b;第一次相遇中,慢指针须走步数 a+b−x<a+b,其中 x 为双指针重合点与环入口距离;因此总体为线性复杂度;
② 空间复杂度:O(1),双指针使用常数大小的额外空间。

代码实现(思路一(哈希表)):
ListNode *detectCycle1(ListNode *head) {
	unordered_set<ListNode*> mp_set;
	//创建一个哈希集合用于存储遍历过的链表结点,如果当前遍历的结点不在哈希集合中则存入集合,如果前遍历的结点存在哈希集合中(第一个)则为链表开始入环的第一个节点,返回该结点程序结束。
	while(head!=nullptr){
		if(mp_set.count(head)){
			return head;
		}else{
			mp_set.insert(head);
			head=head->next;
		}
	}
	return nullptr;
}
代码实现(思路二(快慢指针)):
ListNode *detectCycle2(ListNode *head) {
	ListNode *slow=head,*fast=head;
	//如果是无环的情况便返回,存在环则slow=fast结束循环 
	while(true){ 
		if(fast==nullptr||fast->next==nullptr){
			return nullptr;
		}
		fast=fast->next->next;
		slow=slow->next;
		if(fast==slow){
			break;
		}
	}
	//将fast更改为首节点位置,这里fast和slow移动一步,相遇节点为开始入环的第一个节点 
	fast=head;
	while(fast!=slow){
		fast=fast->next;
		slow=slow->next;
	}
	return fast;

}

以思路二为例完成代码调试

#include<iostream>
#include<vector>
#include<unordered_set>
using namespace std;

struct ListNode{
	int val;
	ListNode *next;
	ListNode(int x):val(x),next(nullptr){}
};

//尾插法创建单链表 
ListNode* createList(const vector<int> &a){
	ListNode *head=nullptr,*tail=nullptr;
	for(const auto &val:a){
		ListNode *newNode=new ListNode(val);
		if(head==nullptr){
			head=newNode;
			tail=newNode;
		}else{
			tail->next=newNode;
			tail=newNode;
		}
	}
	return head;
}

//将单链表变成环形单链表(这里只是末尾存在环的情况) 
ListNode* createCircularList(ListNode *head,int pos){
	//无环则返回
	if(pos==-1){
		return head;
	} 
	ListNode *posNode=head;
	//找到环的入口
	while(pos){
		posNode=posNode->next;
		--pos;
	}
	//找到链表的末尾
	ListNode *tail=posNode;
	while(tail->next!=nullptr){
		tail=tail->next;
	}
	//想成环
	tail->next=posNode;
	return head;
} 

//方法二(快慢指针)
ListNode *detectCycle2(ListNode *head) {
	ListNode *slow=head,*fast=head;
	//如果是无环的情况便返回,存在环则slow=fast结束循环 
	while(true){ 
		if(fast==nullptr||fast->next==nullptr){
			return nullptr;
		}
		fast=fast->next->next;
		slow=slow->next;
		if(fast==slow){
			break;
		}
	}
	//将fast更改为首节点位置,这里fast和slow移动一步,相遇节点为开始入环的第一个节点 
	fast=head;
	while(fast!=slow){
		fast=fast->next;
		slow=slow->next;
	}
	return fast;
}
//主函数
int main(){
	vector<int> a={3,2,0,-4};
	int pos=1;
	ListNode *head=createList(a);
	ListNode *cir_head=createCircularList(head,pos);
	ListNode *ans=detectCycle2(cir_head);
	if(ans!=nullptr){
		cout<<"链表开始入环的第一个结点值为:"<<ans->val; 
	}else{
		cout<<"链表没有开始入环的第一个结点";
	}
	return 0;
}

unordered_map和unordered_set对比及用法请点击此链接
ListNode(int x):val(x),next(nullptr){}解读请点击此链接
LeetCode 热题 100_环形链表 II(26_142)原题链接

欢迎大家和我沟通交流(✿◠‿◠)

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

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

相关文章

如何通过看板进行跨境电商的圣诞商品数据分析与优化选品流程?

引言 随着圣诞季的临近&#xff0c;跨境电商迎来了重要的销售时机。选品工作对于跨境电商的成功至关重要&#xff0c;直接关系到销售业绩和利润。本文结合相关网页信息&#xff0c;深入探讨跨境电商在圣诞期间如何利用信息整合工具展开选品工作&#xff0c;并优化选品流程。同…

PHP开发设计模式:单例模式

PHP开发设计模式&#xff1a;单例模式 特点&#xff1a; 三私一公&#xff1a;私有的静态变量&#xff08;存放实例&#xff09;&#xff0c;私有的构造方法&#xff08;防止创建实例&#xff09;&#xff0c;私有的克隆方法 (防止克隆对象)&#xff0c;公有的静态方法&#…

使用HTML获取商品详情:技术实现与最佳实践

1. 引言 在电子商务领域&#xff0c;获取商品详情是提升用户体验和增强网站功能性的关键。本文将探讨如何使用HTML结合其他技术手段获取商品详情&#xff0c;并展示如何将这些信息有效地呈现给用户。 2. 理解商品详情页面的结构 在开始编码之前&#xff0c;我们需要了解商品…

MR30分布式IO在新能源领域加氢站的应用

导读 氢能被誉为21世纪最具发展潜力的清洁能源&#xff0c;氢能科技创新和产业发展持续得到各国青睐。氢能低碳环保&#xff0c;燃烧的产物只有水&#xff0c;是用能终端实现绿色低碳转型的重要载体。氢能产业链分别为上游制氢、中游储运以及下游用氢。上游制氢工艺目前大部分…

WEB安全基础知识

WAF全称为Web Application Firewall&#xff08;网页应用防火墙&#xff09;是一种专门设计用来保护web应用免受各种网络攻击的安全防护措施。它位于客户端与服务器之间&#xff0c;监控和过滤HTTP流量&#xff0c;从而拦截恶意请求、识别并防御常见的web攻击。 WAF的主要功能…

【数据结构】B树家族解析:B树、B+树与B*树的理论与B树插入实现(C++)

文章目录 一、常见的搜索结构二、B树2.1 B树概念2.2 开销 三、代码实现3.1 B树节点的设计3.2 B树设计3.3 插入操作实现1. 查找插入位置&#xff08;Find 函数&#xff09;2. 插入关键字到节点&#xff08;InsertKey 函数&#xff09;3. 处理节点分裂&#xff08;Insert 函数&am…

protobuf c++开发快速上手指南

1、环境准备 在c环境使用 protobuf&#xff0c;需要安装protobuf runtime以及protobuf的编译器&#xff1a;protoc&#xff0c;其作用如下表格&#xff1a; 需要安装的环境作用protoc将proto文件编译成c源码protobuf runtime编译c源码需要链接到protobuf库 注意&#xff1a;…

【实践·专业课】内存管理-存储管理-文件系统

1. 基于Linux的简单区块链实现 1.1. 环境准备 确保使用的 Linux 系统&#xff08;如 Ubuntu、CentOS 等&#xff09;已安装 Python 3。 在终端输入python3命令&#xff0c;若出现 Python 解释器的版本信息等提示&#xff0c;则表示已安装&#xff1b; 若提示未找到命令&…

科技潮头浪接天,一桥飞架两界连。EthernetIP转Profinet互译连

本案例介绍的是西门子1200PLC通过稳联技术PROFINET转EtherNetIP网关&#xff08;WL-ABC2006&#xff09;连接HCS-6100系统配置案例。 打开稳联技术Ethernetip转profient网关(WL-ABC2006)配置软件&#xff0c;因为网关作为EtherNetIP从站&#xff0c;所以选择PN2EIP。设置网关Pr…

【网络篇】TCP知识

TCP首部格式&#xff1f; 为什么需要 TCP 协议&#xff1f; TCP 工作在哪一层&#xff1f; IP 层是不可靠的&#xff0c;它不保证网络包的交付、不保证网络包的按序交付也不保证网络包中的数据的完整性。如果需要保障网络数据包的可靠性&#xff0c;那么就需要由上层&#xff0…

PDFMathTranslate,PDF多语言翻译,批量处理,学术论文,双语对照(WIN/MAC)

分享一个非常实用的PDF文档翻译项目——PDFMathTranslate。作为一个经常逛GitHub的开发者&#xff0c;我总喜欢翻看各种项目附带的论文&#xff0c;虽然大多时候是瞎研究&#xff0c;但却乐在其中。该项目能够完美保留公式、图表、目录和注释&#xff0c;对于需要阅读外文文献的…

Ape-DTS:开源 DTS 工具,助力自建 MySQL、PostgreSQL 迁移上云

Ape-DTS 是一款高效、轻量级且功能强大的开源工具&#xff0c;专注于解决数据迁移、同步、校验、订阅与加工的需求。无论是将自建的 MySQL/PostgreSQL 数据库迁移到云端&#xff0c;还是在不同数据库间进行数据迁移&#xff0c;Ape-DTS 都能为您提供便捷且可靠的解决方案。它特…

【经典论文阅读】Latent Diffusion Models(LDM)

Latent Diffusion Models High-Resolution Image Synthesis with Latent Diffusion Models 摘要 动机&#xff1a;在有限的计算资源下进行扩散模型训练&#xff0c;同时保持质量和灵活性 引入跨注意力层&#xff0c;以卷积方式实现对一般条件输入&#xff08;如文本或边界框…

使用torch模拟 BMM int8量化计算。

使用torch模型BMM int8计算。 模拟&#xff1a;BMM->softmax->BMM 计算流程 import torch import numpy as np torch.manual_seed(777) def int8_quantize_per_token(x: torch.Tensor, axis: int -1, attnsFalse):if x.dtype ! torch.float32:x x.type(torch.float32)…

Leetcode 每日一题 219.存在重复元素 II

目录 问题描述 输入输出格式 示例 算法分析 过题图片 代码实现 复杂度分析 题目链接 总结 问题描述 给定一个整数数组nums和一个整数k&#xff0c;我们需要判断数组中是否存在两个不同的索引i和j&#xff0c;使得nums[i] nums[j]且|i - j| < k。如果存在这样的i和…

ragflow连不上ollama的解决方案

由于前期wsl默认装在C盘&#xff0c;后期部署好RagFlow后C盘爆红&#xff0c;在连接ollama的时候一直在转圈圈&#xff0c;问其他人没有遇到这种情况&#xff0c;猜测是因为内存不足无法加载模型导致&#xff0c;今天重新在E盘安装wsl 使用wsl装Ubuntu Win11 wsl-安装教程 如…

PR的选择与移动

选择工具 可以选择序列上的剪辑&#xff0c;如果需要多选可以按住shift键选中多个剪辑 CtrlA&#xff1a;可以进行全选 编组 选中多个剪辑后“右键-编组“可以将所选的剪辑连接在一起。这时单击任意剪辑都可以选中全部 向前选择轨道工具与向后选择轨道工具 向前选择轨道工具…

使用C#基于ADO.NET编写MySQL的程序

MySQL 是一个领先的开源数据库管理系统。它是一个多用户、多线程的数据库管理系统。MySQL 在网络上特别流行。MySQL 数据库可在大多数重要的操作系统平台上使用。它可在 BSD Unix、Linux、Windows 或 Mac OS 上运行。MySQL 有两个版本&#xff1a;MySQL 服务器系统和 MySQL 嵌入…

Python3中赋值运算符说明二

一. 简介 前面文章简单学习了 Python3中一些赋值运算符&#xff0c;文章如下&#xff1a; Python3中赋值运算符上篇-CSDN博客 本文继续学习 Python3中另外一些赋值运算符。 二. Python3 中赋值运算符 1. Python3 中赋值运算符 前一篇文章简单学习了 Python3 中的一些赋值…

如何在 Ubuntu 22.04 上安装和使用 Apache Kafka

简介 Apache Kafka是一个高性能、低延迟的分布式流处理平台&#xff0c;广泛用于构建实时数据管道和流式应用。本文将指导你如何在Ubuntu 22.04系统上快速部署Apache Kafka&#xff0c;让你体验到Kafka在处理大规模实时数据流方面的强大能力。通过本教程&#xff0c;你将学会如…