【LeetCode Solutions】LeetCode 160 ~ 165 题解

news2025/4/13 10:23:10

CONTENTS

  • LeetCode 160. 相交链表(简单)
  • LeetCode 162. 寻找峰值(中等)
  • LeetCode 164. 最大间距(中等)
  • LeetCode 165. 比较版本号(中等)

LeetCode 160. 相交链表(简单)

【题目描述】

给你两个单链表的头节点 headAheadB,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

图示两个链表在节点 c1 开始相交:

在这里插入图片描述

题目数据保证整个链式结构中不存在环

注意,函数返回结果后,链表必须保持其原始结构

自定义评测:

评测系统的输入如下(你设计的程序不适用此输入):

  • intersectVal:相交的起始节点的值。如果不存在相交节点,这一值为 0。
  • listA:第一个链表。
  • listB:第二个链表。
  • skipA:在 listA 中(从头节点开始)跳到交叉节点的节点数。
  • skipB:在 listB 中(从头节点开始)跳到交叉节点的节点数。

评测系统将根据这些输入创建链式数据结构,并将两个头节点 headAheadB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被视作正确答案

【示例 1】

在这里插入图片描述

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
— 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。

【示例 2】

在这里插入图片描述

输入:intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [1,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

【示例 3】

在这里插入图片描述

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:No intersection
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null。

【提示】

listA 中节点数目为 m m m
listB 中节点数目为 n n n
1 < = m , n < = 3 ∗ 1 0 4 1 <= m, n <= 3 * 10^4 1<=m,n<=3104
1 < = N o d e . v a l < = 1 0 5 1 <= Node.val <= 10^5 1<=Node.val<=105
0 < = s k i p A < = m 0 <= skipA <= m 0<=skipA<=m
0 < = s k i p B < = n 0 <= skipB <= n 0<=skipB<=n
如果 listAlistB 没有交点,intersectVal 为 0
如果 listAlistB 有交点,intersectVal == listA[skipA] == listB[skipB]

进阶:你能否设计一个时间复杂度 O ( m + n ) O(m + n) O(m+n)、仅用 O ( 1 ) O(1) O(1) 内存的解决方案?


【分析】

本题的思想也具有跳跃性,我们用两个指针 pq 分别从 headAheadB 开始走,当 p 走到尽头后就从 headB 再重新开始走,当 q 走到尽头后就从 headA 再重新开始走。

假设 headA 到相交点的距离为 a a aheadB 到相交点的距离为 b b b,相交点到终点的距离为 c c c,那么 pheadA 走到尽头再从 headB 走到相交点的距离为 a + c + b a + c + b a+c+b;同理 qheadB 走到尽头再从 headA 走到相交点的距离也为 b + c + a b + c + a b+c+a

因此这样在两个指针都走到尽头并交换起点继续走的时候一定能在链表的相交点相遇,如果没有相交,那么最后两个指针会同时为空,这样两个指针也是相等,因此代码就很好写,只要两个指针走到相等的时候就能判断结果。


【代码】

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *p = headA, *q = headB;
        while (p != q) p = p ? p->next : headB, q = q ? q->next : headA;
        return p;
    }
};

LeetCode 162. 寻找峰值(中等)

【题目描述】

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。

你可以假设 nums[-1]nums[n] 为负无穷大。

你必须实现时间复杂度为 O ( l o g n ) O(log n) O(logn) 的算法来解决此问题。

【示例 1】

输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。

【示例 2】

输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5 
解释:你的函数可以返回索引 1,其峰值元素为 2;
     或者返回索引 5, 其峰值元素为 6。

【提示】

1 < = n u m s . l e n g t h < = 1000 1 <= nums.length <= 1000 1<=nums.length<=1000
− 2 31 < = n u m s [ i ] < = 2 31 − 1 -2^{31} <= nums[i] <= 2^{31} - 1 231<=nums[i]<=2311
对于所有有效的 i i i 都有 nums[i] != nums[i + 1]


【分析】

本题展现了二分不一定要求数组具有单调性。首先本题不可能无解,设左端点下标为 i i i,那么如果 i + 1 i + 1 i+1 是降序的,那么 i i i 就是峰值,因此只能是升序;同理如果 i + 2 i + 2 i+2 是降序的,那么 i + 1 i + 1 i+1 就是峰值,因此还是只能升序。容易发现如果整个序列中间某个地方出现了降序一定都会产生峰值,如果整个序列都是升序,那么右端点就是峰值。所以无论如何都至少存在一个峰值。

现在来看看如何二分确定峰值在哪。假设二分的中点为 nums[mid],将其与下一个数进行比较:

  • nums[mid] < nums[mid + 1]:右半部分区间一定存在峰值,因为右半区间只要出现降序就一定存在峰值,否则如果全是升序那么右端点也会是峰值,而左半部分如果全是升序是可能不存在峰值的;
  • nums[mid] > nums[mid + 1]:左半部分区间一定存在峰值,因为左半区间只要出现升序再降序就一定存在峰值,否则如果全是降序那么左端点也会是峰值。

本题的边界情况需要考虑清楚,可以画个图结合代码的注释进行理解。


【代码】

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int l = 0, r = nums.size() - 1;
        while (l < r) {
            int mid = l + r >> 1;  // mid 是下取整,因此 mid + 1 不可能越界,mid 等于 n 的唯一情况是 l = r = n
            if (nums[mid] > nums[mid + 1]) r = mid;  // 这种情况 nums[mid] 可能是峰值
            else l = mid + 1;  // nums[mid] < nums[mid + 1] 时 nums[mid] 不可能是峰值
        }
        return r;
    }
};

LeetCode 164. 最大间距(中等)

【题目描述】

给定一个无序的数组 nums,返回数组在排序之后,相邻元素之间最大的差值。如果数组元素个数小于 2,则返回 0。

您必须编写一个在「线性时间」内运行并使用「线性额外空间」的算法。

【示例 1】

输入: nums = [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。

【示例 2】

输入: nums = [10]
输出: 0
解释: 数组元素个数小于 2,因此返回 0。

【提示】

1 < = n u m s . l e n g t h < = 1 0 5 1 <= nums.length <= 10^5 1<=nums.length<=105
0 < = n u m s [ i ] < = 1 0 9 0 <= nums[i] <= 10^9 0<=nums[i]<=109


【分析】

本题的思路很难。首先我们遍历一遍数组找出最大值 MAX 和最小值 MIN,然后将 MIN ~ MAX 分成若干个等长的区间(假设区间统一为左开右闭),这样每个区间内可能会有若干个数,也可能一个数都没有。

划分完区间需要满足答案不在每个区间内部,即区间内相邻元素的差值均小于最大差值。那么这样答案就在区间之间,只需要维护每个区间的最小值与最大值,然后遍历一遍每个区间,答案一定是某个区间的最小值与其前一个区间的最大值之差。

那么区间长度如何确定才能满足条件?假设分为 n − 1 n - 1 n1 个区间,每个区间长度为 l e n len len,那么区间内最多有 l e n len len 个数(假如区间为 (0, len]),区间内的最大差值为 l e n − 1 len - 1 len1。如果每个区间都取最大差值还无法覆盖整个区间,说明全局的最大差值不在任何一个区间内,即 ( n − 1 ) ( l e n − 1 ) < M A X − M I N (n - 1)(len - 1) < MAX - MIN (n1)(len1)<MAXMIN,化简后可以得到 l e n len len 的范围:

( n − 1 ) ( l e n − 1 ) ≤ M A X − M I N − 1 = l e n − 1 ≤ ( M A X − M I N − 1 ) / ( n − 1 ) = l e n ≤ ( M A X − M I N + n − 2 ) / ( n − 1 ) (n - 1)(len - 1) \le MAX - MIN - 1 \\ = len - 1 \le (MAX - MIN - 1) / (n - 1) \\ = len \le (MAX - MIN + n - 2) / (n - 1) (n1)(len1)MAXMIN1=len1(MAXMIN1)/(n1)=len(MAXMIN+n2)/(n1)


【代码】

class Solution {
public:
    int maximumGap(vector<int>& nums) {
        struct Range {
            int min, max;
            bool has_num;  // 区间是否存在元素
            Range() : min(INT_MAX), max(INT_MIN), has_num(false) {}
        };
        int n = nums.size();
        int MIN = INT_MAX, MAX = INT_MIN;
        for (int x: nums) MIN = min(MIN, x), MAX = max(MAX, x);
        if (n < 2 || MAX == MIN) return 0;  // 还可以特判一下是不是所有元素都相同
        vector<Range> r(n - 1);
        int len = (MAX - MIN + n - 2) / (n - 1);  // 区间长度
        for (int x: nums) {
            if (x == MIN) continue;  // 由于区间是左开右闭的,因此最小值不算在任何区间内
            int k = (x - MIN - 1) / len;  // 区间索引,注意要先减去 MIN,例如第一个区间为 [MIN, MIN + len - 1]
            r[k].min = min(r[k].min, x), r[k].max = max(r[k].max, x), r[k].has_num = true;
        }
        int res = 0;
        for (int i = 0, last = MIN; i < n - 1; i++)  // last 为上一个区间的最大值
            if (r[i].has_num) res = max(res, r[i].min - last), last = r[i].max;
        return res;
    }
};

LeetCode 165. 比较版本号(中等)

【题目描述】

给你两个版本号字符串 version1version2,请你比较它们。版本号由被点 '.' 分开的修订号组成。修订号的值是它转换为整数并忽略前导零。

比较版本号时,请按从左到右的顺序依次比较它们的修订号。如果其中一个版本字符串的修订号较少,则将缺失的修订号视为 0。

返回规则如下:

  • 如果 version1 < version2 返回 -1;
  • 如果 version1 > version2 返回 1;
  • 除此之外返回 0。

【示例 1】

输入:version1 = "1.2", version2 = "1.10"
输出:-1
解释:version1 的第二个修订号为 "2",version2 的第二个修订号为 "10":2 < 10,所以 version1 < version2。

【示例 2】

输入:version1 = "1.01", version2 = "1.001"
输出:0
解释:忽略前导零,"01" 和 "001" 都代表相同的整数 "1"。

【示例 3】

输入:version1 = "1.0", version2 = "1.0.0.0"
输出:0
解释:version1 有更少的修订号,每个缺失的修订号按 "0" 处理。

【提示】

1 < = v e r s i o n 1. l e n g t h , v e r s i o n 2. l e n g t h < = 500 1 <= version1.length, version2.length <= 500 1<=version1.length,version2.length<=500
version1version2 仅包含数字和 '.'
version1version2 都是有效版本号
version1version2 的所有修订号都可以存储在 32 位整数中


【分析】

本题就很简单了,直接按照提议模拟即可,遍历两个字符串将对应位置的版本号转换为整数进行比较。


【代码】

class Solution {
public:
    int compareVersion(string version1, string version2) {
        int n = version1.size(), m = version2.size();
        int i = 0, j = 0;
        while (i < n || j < m) {
            int a = i, b = j, v1 = 0, v2 = 0;
            while (a < n && version1[a] != '.') v1 = v1 * 10 + (version1[a] - '0'), a++;  // 不加括号可能会溢出
            while (b < m && version2[b] != '.') v2 = v2 * 10 + (version2[b] - '0'), b++;
            if (v1 < v2) return -1;
            else if (v1 > v2) return 1;
            i = a + 1, j = b + 1;
        }
        return 0;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Openssl升级至openssl9.8p1含全部踩坑内容

1、安装依赖包基础条件 yum install gcc yum install gcc-c yum install perl yum install perl-IPC-Cmd yum install pam yum install pam-devel sudo yum install perl-Data-Dumper 问题一&#xff1a;提示yum不可用 镜像源问题更换阿里源即可 wget -O /etc/yum.repos.d/…

二战蓝桥杯所感

&#x1f334; 前言 今天是2025年4月12日&#xff0c;第十六届蓝桥杯结束&#xff0c;作为二战的老手&#xff0c;心中还是颇有不甘的。一方面&#xff0c;今年的题目比去年简单很多&#xff0c;另一方面我感觉并没有把能拿的分都拿到手&#xff0c;这是我觉得最遗憾的地方。不…

查看手机在线状态,保障设备安全运行

手机作为人们日常生活中不可或缺的工具&#xff0c;承载着沟通、工作、娱乐等多种功能。保障手机设备的安全运行是我们每个人都非常重要的任务&#xff0c;而了解手机的在线状态则是其中的一环。通过挖数据平台提供的在线查询工具&#xff0c;我们可以方便快捷地查询手机号的在…

#关于数据库中的时间存储

✅ 一、是否根据“机器当前时区”得到本地时间再转 UTC&#xff1f; 结论&#xff1a;是的&#xff0c;但仅对 TIMESTAMP 字段生效。 数据库&#xff08;如 MySQL&#xff09;在插入 TIMESTAMP 类型数据时&#xff1a; 使用当前会话的时区&#xff08;默认跟随系统时区&#…

第16届蓝桥杯省赛python B组个人题解

文章目录 前言ABCDEFGH 前言 仅个人回忆&#xff0c;不保证正确性 貌似都是典题&#xff0c;针对python的长代码模拟题也没有&#xff0c;一小时速通了&#xff0c;希望不要翻车。 更新&#xff1a;B、G翻车了。。 A 答案&#xff1a;103 B 应该是按长度排序&#xff0c;然后…

lvs+keepalived+dns高可用

1.配置dns相关服务 1.1修改ip地址主机名 dns-master: hostnamectl hostname lvs-master nmcli c modify ens160 ipv4.method manual ipv4.addresses 10.10.10.107/24 ipv4.gateway 10.10.10.2 ipv4.dns 223.5.5.5 connection.autoconnect yes nmcli c up ens160dns-salve: h…

Spark RDD相关概念

Spark运行架构与核心组件 1.Spark运行梁构 spark运行架构包括master和slave两个主要部分。master负责管理整个集群的作业任务调度&#xff0c;而slave则负责实际执行任务。 dirver是Spark驱动器节点&#xff0c;负责执行Spark任务中的main方法&#xff0c;将用户程序转换成作业…

SD + Contronet,扩散模型V1.5+约束条件后续优化:保存Canny边缘图,便于视觉理解——stable diffusion项目学习笔记

目录 前言 背景与需求 代码改进方案 运行过程&#xff1a; 1、Run​编辑 2、过程&#xff1a; 3、过程时间线&#xff1a; 4、最终效果展示&#xff1a; 总结与展望 前言 机器学习缺点之一&#xff1a;即不可解释性。最近&#xff0c;我在使用stable diffusion v1.5 Co…

【ROS2】行为树:BehaviorTree

1、简介 与状态机不同,行为树强调执行动作,而不是状态之间的转换。 行为树是可组合的。可以重复使用简单的行为来构建复杂的行为。 在游戏领域,行为树已经比较流行了。主要用于维护游戏角色的各种动作和状态。 ROS2的导航框架Navigation2中引入了行为树来组织机器人的工作流…

《JVM考古现场(十八):造化玉碟·用字节码重写因果律的九种方法》

"鸿蒙初判&#xff01;当前因果链突破十一维屏障——全体码农修士注意&#xff0c;《JVM考古现场&#xff08;十八&#xff09;》即将渡劫飞升&#xff01;" 目录 上卷阴阳交缠 第一章&#xff1a;混沌初开——JVM因果律的量子纠缠 第二章&#xff1a;诛仙剑阵改—…

使用nuxt3+tailwindcss4+@nuxt/content3在页面渲染 markdown 文档

nuxt3tailwindcss在页面渲染 markdown 文档 页面效果 依赖 “nuxt/content”: “^3.4.0” “tailwindcss”: “^4.0.10” “nuxt”: “^3.16.2” “tailwindcss/vite”: “^4.0.10” tailwindcss/typography (这个是格式化 md 样式用的) 注意&#xff1a; 这里nuxt/content…

Linux网络编程——详解网络层IP协议、网段划分、路由

目录 一、前言 二、IP协议的认识 1、什么是IP协议&#xff1f; 2、IP协议报头 三、网段划分 1、初步认识IP与路由 2、IP地址 I、DHCP动态主机配置协议 3、IP地址的划分 I、CIDR设计 II、子网数目的计算 III、子网掩码的确定 四、特殊的IP地址 五、IP地址的数量限…

【图像生成之21】融合了Transformer与Diffusion,Meta新作Transfusion实现图像与语言大一统

论文&#xff1a;Transfusion: Predict the Next Token and Diffuse Images with One Multi-Modal Model 地址&#xff1a;https://arxiv.org/abs/2408.11039 类型&#xff1a;理解与生成 Transfusion模型‌是一种将Transformer和Diffusion模型融合的多模态模型&#xff0c;旨…

Microsoft Office 如何启用和正常播放 Flash 控件

对于新安装的 Office 默认是不支持启用 Flash 组件的&#xff0c;Flash 组件会无法播放或者黑屏。 本片文章就带你解决这个问题&#xff0c;相关资料都在下方连接内。前提概要&#xff0c;教程对应的版本是 mso16&#xff0c;即 Office 2016 及更新版本&#xff0c;以及 365 等…

定位改了IP属地没变怎么回事?一文解析

明明用虚拟定位软件将手机位置改到了“三亚”&#xff0c;为何某某应用评论区显示的IP属地还是“北京”&#xff1f;为什么切换了代理IP&#xff0c;平台却似乎“无视”这一变化&#xff1f; 在“IP属地显示”功能普及后&#xff0c;许多用户尝试通过技术手段隐藏真实位置&…

《深入理解生命周期与作用域:以C语言为例》

&#x1f680;个人主页&#xff1a;BabyZZの秘密日记 &#x1f4d6;收入专栏&#xff1a;C语言 &#x1f30d;文章目入 一、生命周期&#xff1a;变量的存在时间&#xff08;一&#xff09;生命周期的定义&#xff08;二&#xff09;C语言中的生命周期类型&#xff08;三&#…

一个插件,免费使用所有顶级大模型(Deepseek,Gpt,Grok,Gemini)

DeepSider是一款集成于浏览器侧边栏的AI对话工具&#xff0c;可免费使用所有顶级大模型 包括GPT-4o&#xff0c;Grok3,Claude 3.5 Sonnet,Claude 3.7,Gemini 2.0&#xff0c;Deepseek R1满血版等 以极简交互与超快的响应速度&#xff0c;完成AI搜索、实时问答、内容创作、翻译、…

智能车摄像头开源—9 动态权、模糊PID、速度决策、路径优化

目录 一、前言 二、动态权 1.概述 2.偏差值加动态权 三、模糊PID 四、速度决策 1.曲率计算 2.速度拟合 3.速度控制 五、路径 六、国赛视频 一、前言 在前中期通过识别直道、弯道等元素可进行加减速操作实现速度的控制&#xff0c;可进一步缩减一圈的运行速度&#xff…

《2025蓝桥杯C++B组:D:产值调整》

**作者的个人gitee**​​ 作者的算法讲解主页▶️ 每日一言&#xff1a;“泪眼问花花不语&#xff0c;乱红飞过秋千去&#x1f338;&#x1f338;” 题目 二.解题策略 本题比较简单&#xff0c;我的思路是写三个函数分别计算黄金白银铜一次新产值&#xff0c;通过k次循环即可获…

2025认证杯一阶段各题需要使用的模型或算法(冲刺阶段)

A题&#xff08;小行星轨迹预测&#xff09; 问题一&#xff1a;三角测量法、最小二乘法、空间几何算法、最优化方法 问题二&#xff1a;Gauss/Laplace轨道确定方法、差分校正法、数值积分算法&#xff08;如Runge-Kutta法&#xff09;、卡尔曼滤波器 B题&#xff08;谣言在…