算法打卡12天
19.链表相交
(力扣面试题 02.07. 链表相交)
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
图示两个链表在节点 c1
开始相交**:**
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [0,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
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。
解题思路
题目要求找到两个单链表的第一个公共节点。核心思路是利用链表长度的差值来对齐链表尾部,从而让两个指针能够同时遍历并找到交点。
- 计算链表长度:
- 遍历链表 A 和链表 B,分别计算它们的长度
lenA
和lenB
。
- 遍历链表 A 和链表 B,分别计算它们的长度
- 对齐链表尾部:
- 如果链表 B 比链表 A 长,交换它们的长度和头指针,确保链表 A 是较长的链表。
- 计算长度差
gap = lenA - lenB
,让较长的链表(链表 A)的指针先走gap
步,这样两个链表的尾部对齐。
- 同时遍历链表:
- 从对齐后的起点开始,同时遍历链表 A 和链表 B。
- 如果两个指针相遇(即
curA == curB
),说明找到了第一个公共节点,直接返回该节点。 - 如果遍历完都没有相遇,则返回
NULL
,表示两个链表没有交点。
代码
#include <iostream>
#include <algorithm>struct ListNode
{int val;ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};class Solution
{
public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB){// 交点不是数值相等,而是指针相等ListNode *curA = headA;ListNode *curB = headB;int lenA = 0;int lenB = 0;// 求链表A的长度while (curA != NULL){lenA++;curA = curA->next;}// 求链表B的长度while (curB != NULL){lenB++;curB = curB->next;}// 重新指向链表A和B的头节点 curA 和 curB现在是NULLcurA = headA;curB = headB;// 如果链表B比链表A长,交换它们的长度和头指针if (lenB > lenA){std::swap(lenA, lenB);std::swap(curA, curB);}// 求长度差int gap = lenA - lenB;// 让curA先走gap步,这样两个链表的尾部对齐while (gap--){curA = curA->next;}// 同时遍历curA和curBwhile (curA != NULL){// 如果两个指针相遇,说明找到了第一个公共节点(返回指针)if (curA == curB){return curA;}// 移动链表的指针curA = curA->next;curB = curB->next;}return NULL;}
};
- 时间复杂度:O(n + m)
- 空间复杂度:O(1)
39.逆波兰表达式求值
(力扣150题)
给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
- 有效的算符为
'+'
、'-'
、'*'
和'/'
。 - 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
示例 1:
输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
提示:
1 <= tokens.length <= 104
tokens[i]
是一个算符("+"
、"-"
、"*"
或"/"
),或是在范围[-200, 200]
内的一个整数
逆波兰表达式:
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
- 平常使用的算式则是一种中缀表达式,如
( 1 + 2 ) * ( 3 + 4 )
。 - 该算式的逆波兰表达式写法为
( ( 1 2 + ) ( 3 4 + ) * )
。
逆波兰表达式主要有以下两个优点:
- 去掉括号后表达式无歧义,上式即便写成
1 2 + 3 4 + *
也可以依据次序计算出正确结果。 - 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
解题思路
- 初始化栈:
- 使用一个栈(
stack<long long>
)来存储操作数。栈的类型为long long
,以支持较大的整数运算。
- 使用一个栈(
- 遍历表达式:
- 遍历 RPN 表达式的每个元素(
tokens
)。每个元素可以是数字或运算符。
- 遍历 RPN 表达式的每个元素(
- 处理数字:
- 如果当前元素是数字(即不是运算符),将其转换为
long long
类型并压入栈中。这里使用std::stoll
函数将字符串转换为数字。
- 如果当前元素是数字(即不是运算符),将其转换为
- 处理运算符:
- 如果当前元素是运算符(
+
,-
,*
,/
),需要从栈中弹出两个操作数。 - 检查栈中是否有足够的操作数(至少两个)。如果不足,说明表达式不合法,打印错误信息并返回错误码
0
。 - 弹出栈顶的两个操作数(
num1
和num2
),注意顺序:num1
是栈顶元素,num2
是第二个元素。 - 根据运算符对两个操作数进行运算,并将结果压入栈中。
- 如果当前元素是运算符(
- 检查最终结果:
- 遍历结束后,检查栈中是否只剩下一个元素。如果栈中不止一个元素,说明表达式不合法,打印错误信息并返回错误码
0
。 - 如果栈中只剩下一个元素,该元素即为 RPN 表达式的结果。
- 遍历结束后,检查栈中是否只剩下一个元素。如果栈中不止一个元素,说明表达式不合法,打印错误信息并返回错误码
- 返回结果:
- 弹出栈顶元素并返回其值。
代码实现的逻辑
- 栈的使用:栈用于存储操作数,支持后进先出(LIFO)的操作,非常适合处理 RPN 表达式。
- 错误处理:通过检查栈的大小来确保每次运算符操作时有足够的操作数,避免运行时错误。
- 最终检查:确保栈中只剩下一个元素,验证 RPN 表达式的合法性
#include <iostream>
#include <stack>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;class Solution
{public:int evalRPN(vector<string> &tokens){// 栈stack<long long> st;for (int i = 0; i < tokens.size(); i++){// 如果遍历到运算符if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/"){// 检查栈中是否有足够的元素if(st.size() < 2){perror("Error: Not enough operands for the operator");return 0;}// 获取栈顶元素 就是要运算的数字long long num1 = st.top();// 弹出栈st.pop();long long num2 = st.top();st.pop();// 计算数值 再加入栈里面if (tokens[i] == "+"){st.push(num2 + num1);}if (tokens[i] == "-"){st.push(num2 - num1);}if (tokens[i] == "*"){st.push(num2 * num1);}if (tokens[i] == "/"){st.push(num2 / num1);}}// 如果遍历到数字 加入栈else{// std::stoll,表示 “string to long long”,也就是将字符串转换为 long long 类型的整数。st.push(std::stoll(tokens[i]));}}// 如果最后结果不是一个元素 表达式不合法if(st.size() != 1){perror("Error: Invalid RPN expression");return 0;}// 统计最后的数值 此时栈就一个元素(结果)long long result = st.top();// 弹出st.pop();return result;}
};
- 时间复杂度: O(n)
- 空间复杂度: O(n)
40.滑动窗口最大值
(力扣239题)
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 31 [3 -1 -3] 5 3 6 7 31 3 [-1 -3 5] 3 6 7 51 3 -1 [-3 5 3] 6 7 51 3 -1 -3 [5 3 6] 7 61 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1
输出:[1]
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
解题思路
本题的目标是求解滑动窗口中的最大值。滑动窗口的大小为 k
,随着窗口的滑动,我们需要高效地找到每个窗口的最大值。为了实现这一目标,我们使用了一个自定义的单调队列(Mydeque
)来维护窗口内的元素。
单调队列的特性
- 单调递减:队列中的元素从大到小排列。队列头部始终是当前窗口的最大值。
- 高效移除:当窗口滑动时,窗口外的元素需要被移除。通过
pop
方法,我们检查队列头部是否是窗口外的元素,如果是,则移除。 - 动态维护:当新元素加入窗口时,通过
push
方法,将队列尾部所有小于新元素的值移除,确保队列始终保持单调递减。
算法步骤
- 初始化窗口:将前
k
个元素加入单调队列。 - 记录第一个窗口的最大值:队列头部即为第一个窗口的最大值。
- 滑动窗口:
- 移除窗口外的元素:通过
pop
方法,移除队列头部的窗口外元素。 - 加入新元素:通过
push
方法,将新元素加入队列,并维护队列的单调性。 - 记录当前窗口的最大值:队列头部即为当前窗口的最大值。
- 移除窗口外的元素:通过
- 返回结果:所有窗口的最大值存储在结果数组中。
#include <iostream>
#include <deque>
#include <vector>
class Solution
{// 单调队列(从大到小)
private:class Mydeque{public:// 使用deque来实现单调队列std::deque<int> que;// 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则// 同时pop之前判断队列当前是否为空void pop(int value){if (!que.empty() && value == que.front()){que.pop_front();}}void push(int value){// 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。// 这样就保持了队列里的数值是单调从大到小的了。while (!que.empty() && value > que.back()){// 列尾部的值在滑动窗口中不再有用,可以移除。que.pop_back();}// 没有的话就单纯把值添加到单调队列里que.push_back(value);}// 查询当前队列里的最大值 直接返回队列前端也就是front就可以了。int front(){return que.front();}};public:std::vector<int> maxSlidingWindow(std::vector<int> &nums, int k){Mydeque que;std::vector<int> result;// 先将前k的元素放进队列for (int i = 0; i < k; i++){que.push(nums[i]);}// result 记录前k的元素的最大值result.push_back(que.front());for (int i = k; i < nums.size() ; i++){// 滑动窗口移除最前面元素que.pop(nums[i - k]);// 滑动窗口前加入最后面的元素que.push(nums[i]);// 记录对应的最大值result.push_back(que.front());}return result;}
};
时间复杂度
每个元素最多被加入和移除队列一次,因此时间复杂度为 O(n),其中 n 是数组的长度。
空间复杂度
单调队列的空间复杂度为 O(k),因为队列中最多存储窗口大小的元素。
通过单调队列,我们能够高效地解决滑动窗口的最大值问题,避免
相关文章:

算法打卡12天
19.链表相交 (力扣面试题 02.07. 链表相交) 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。 图示两个链表在节点 c1 开始相交**:** 题目数据…...
OpenCV C++ 学习笔记(四):图像/视频的输入输出(highgui模块 高层GUI和媒体I/O)
文章目录 图片读取创建窗口图片显示图片保存视频输入输出 图片读取 cv::Mat imread( const String& filename, int flags IMREAD_COLOR );enum ImreadModes {IMREAD_UNCHANGED -1, //!< If set, return the loaded image as is (with alpha channel, othe…...
我的创作纪念日——聊聊我想成为一个创作者的动机
2025年6月4日,是我在CSDN写下第一篇技术博客的第1024天。 1024,这个数字对于程序员来说意义非凡,它不仅是内存单位的基础,更是我们这群“码农”的节日符号。而对我来说,它更像是一段旅程的里程碑:从一个曾想…...

蓝桥杯国赛训练 day1 Java大学B组
目录 k倍区间 舞狮 交换瓶子 k倍区间 取模后算组合数就行 import java.util.HashMap; import java.util.Map; import java.util.Scanner;public class Main {static Scanner sc new Scanner(System.in);public static void main(String[] args) {solve();}public static vo…...

PyTorch——非线性激活(5)
非线性激活函数的作用是让神经网络能够理解更复杂的模式和规律。如果没有非线性激活函数,神经网络就只能进行简单的加法和乘法运算,没法处理复杂的问题。 非线性变化的目的就是给我们的网络当中引入一些非线性特征 Relu 激活函数 Relu处理图像 # 导入必…...

OPenCV CUDA模块目标检测----- HOG 特征提取和目标检测类cv::cuda::HOG
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::cuda::HOG 是 OpenCV 的 CUDA 模块中对 HOG 特征提取和目标检测 提供的 GPU 实现。它与 CPU 版本的 cv::HOGDescriptor 类似,但利…...

MATLAB读取文件内容:Excel、CSV和TXT文件解析
MATLAB读取文件内容:Excel、CSV和TXT文件解析 MATLAB 是一款强大的数学与工程计算工具,广泛应用于数据分析、模型构建和图像处理等领域。在处理实际问题时,我们常常需要从文件中读取数据进行分析。本文将介绍如何使用 MATLAB 读取常见的文件…...

Spring MVC 之 异常处理
使用Spring MVC可以很灵活地完成数据的绑定和响应,极大的简化了Java Web的开发。但Spring MVC提供的便利不仅仅如此,使用Spring MVC还可以很便捷地完成项目中的异常处理、自定义拦截器以及文件上传和下载等高级功能。本章将对Spring MVC提供的这些高级功…...
缓存控制HTTP标头设置为“无缓存、无存储、必须重新验证”
文章目录 说明示例核心响应头设置实现原理代码实现1. 原生 Node.js (使用 http 模块)2. Express 框架3. 针对特定路由设置 (Express) 验证方法(使用 cURL)关键注意事项 说明 日期:2025年6月4日。 对于安全内容,请确保缓存控制HT…...

ubuntu24.04 使用apt指令只下载不安装软件
比如我想下载net-tools工具包及其依赖包可以如下指令 apt --download-only install net-tools 自动下载的软件包在/var/cache/apt/archives/目录下...
macOS 上使用 Homebrew 安装redis-cli
在 macOS 上使用 Homebrew 安装 redis-cli(Redis 命令行工具)非常简单,以下是详细步骤: 1. 安装 Redis(包含 redis-cli) 运行以下命令安装 Redis: brew install redis这会安装完整的 Redis 服…...

计算机网络安全问答数据集(1788条) ,AI智能体知识库收集! AI大模型训练数据!
继续收集数据集,话不多说,见下文! 今天分享一个计算机网络安全问答数据集(1788条),适用于AI大模型训练、智能体知识库构建、安全教育系统开发等多种场景! 一、数据特点 结构清晰:共计1788条&…...

WinCC学习系列-高阶应用(WinCC REST通信)
WinCC作为一个经典SCADA系统,它是OT与IT数据无缝集成桥梁,自WinCC7.5版本开始,可以直接提供Rest服务用于其它系统数据访问和操作。 WinCC REST 服务允许外部应用程序访问 WinCC 数据。 外部应用程序可以通过 REST 接口读取和写入 WinCC 组态…...
八、Python模块、包
目录 1. 模块 1.1 什么是模块? 1.2 创建模块 1.3 导入模块 1.4 模块的命名空间 1.5 模块的搜索路径 1.6 模块的重新加载 2. 包 2.1 什么是包? 2.2 创建包 2.3 导入包中的模块 2.4 包的层次结构 3. 模块和包的管理 3.1 安装模块 3.2 卸载模…...

使用交叉编译工具提示stubs-32.h:7:11: fatal error: gnu/stubs-soft.h: 没有那个文件或目录的解决办法
0 前言 使用ST官方SDK提供的交叉编译工具、cmake生成Makefile,使用make命令生成可执行文件提示fatal error: gnu/stubs-soft.h: 没有那个文件或目录的解决办法,如下所示: 根据这一错误提示,按照网上的解决方案逐一尝试均以失败告…...

macOS 连接 Docker 运行 postgres,使用navicat添加并关联数据库
下载 docker注册一个账号,登录 Docker创建 docke r文件 mkdir -p ~/.docker && touch ~/.docker/daemon.json写入配置(全量替换) {"builder": {"gc": {"defaultKeepStorage": "20GB",&quo…...

指针的使用——基本数据类型、数组、结构体
1 引言 对于学习指针要弄清楚如下问题基本可以应付大部分的场景: ① 指针是什么? ② 指针的类型是什么? ③ 指针指向的类型是什么? ④ 指针指向了哪里? 2 如何使用指针 任何东西的学习最好可以总结成一种通用化的…...

TK海外抢单源码/指定卡单
抢单源码,有指定派单,打针,这套二改过充值跳转客服 前端vue 后端php 两端分离 可二开 可以指定卡第几单,金额多少, 前后端开源 PHP7.2 MySQL5.6 前端要www.域名,后端要admin.域名 前端直接静态 伪静…...
Docker MCP 目录和工具包简介:使用 MCP 为 AI 代理提供支持的简单安全方法
目录 Model Context Protocol 势头强劲 — 还需要改进哪些?发现正确的、官方的和/或值得信赖的工具是很困难的复杂的安装和分发身份验证和权限不足Docker 如何帮助解决这些挑战在安全、隔离的容器中轻松发现和运行 MCP 服务器一键式 MCP 客户端集成,内置安全认证企业就绪的 M…...

【Linux】Linux 环境变量
参考博客:https://blog.csdn.net/sjsjnsjnn/article/details/125533127 一、环境变量 1.1 基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数如:我们在编写C/C代码的时候,在链接的时候&am…...

OpenCV在图像上绘制文字示例
OpenCV计算机视觉开发实践:基于Qt C - 商品搜索 - 京东 OpenCV中除了提供绘制各种图形的函数外,还提供了一个特殊的绘制函数,用于在图像上绘制文字。这个函数是putText(),它是命名空间cv中的函数,其声明如下ÿ…...
Java 抗量子算法:构建后量子时代的安全基石
一、量子计算带来的加密挑战 在传统加密体系中,RSA、ECC 等公钥算法依赖大数分解和离散对数问题的难解性。然而,量子计算机的 Shor 算法可在多项式时间内破解这些算法,使现有加密体系面临颠覆性威胁。例如,2048 位 RSA 密钥的破解…...
Kubernetes 集群到 Jumpserver
以下是使用 ServiceAccount Token(令牌) 连接 Kubernetes 集群到 Jumpserver 的 详细分步指南,包括权限配置、Token 获取和常见问题排查。 1. 创建 ServiceAccount 并分配权限 1.1 创建 ServiceAccount 在 Kubernetes 集群中创建一个专用于…...
Android7 Input(十)View 处理Input事件pipeline
概述: 本文主要描述View对InputEvent事件pipeline处理过程。 本文涉及的源码路径 frameworks/base/core/java/android/view/ViewRootImpl.java InputEvent事件处理 View处理input事件是调用doProcessInputEvents方法,如下所示: void doProcessInputEvents() {//…...
图像数据如何表示为概率单纯形
目录 图像数据灰度图像彩色图像概率单纯形条件应用场景 图像数据 图像数据通常由像素值组成,这些像素值可以是灰度值(对于黑白图像)或RGB值(对于彩色图像)。每个像素的值通常在0到255之间。为了将图像数据表示为概率单…...
(11)Service Mesh架构下Java应用实现零信任安全模型
Service Mesh架构下Java应用实现零信任安全模型 📌 TL;DR: 本文详细介绍如何在Service Mesh架构中实现零信任安全模型,包括身份认证、授权控制、加密通信和持续监控四大核心技术,以及与Istio、Envoy等组件的集成方案。 目录 零信任安全模型概述关键技术实现最佳实践Service…...
什么是内网映射?如何将内网ip映射到外网访问?
随着互联网科技和信息技术的快速发展,很多原理及技术开始被应用到互联网信息科技领域,其中内网iP映射就成为非常普通常见的一个操作。那么什么是内网ip映射?如何将内网ip映射到外网? 一、什么是内网ip映射? 简单理解…...

为什么要选择VR看房?VR看房有什么优点?
VR看房:革新传统,重塑体验 在当今社会,虚拟现实(VR)技术正以前所未有的速度渗透到我们生活的各个领域,其中VR看房作为房地产领域的重要创新。本文将讨论为什么要选择VR看房以及VR看房的主要优点࿰…...
linux 串口调试命令 stty
linux 串口调试命令 stty 文章目录 linux 串口调试命令 sttystty 常见命令选项:常用参数:一次性设置串口所有常见参数总结 stty(设置终端行模式)命令是用来配置终端设备(包括串口设备)的输入和输出行为的工…...
C++STL-vector的使用
vector的定义方式 方式1:构造某一个类型的空容器 vector<int> v1;//构造一个int类型的空容器 方式2:构造一个含有n个val的某类型容器 vector<int> v2(10, 2);//构造一个含有10个2的int类型的容器 方式3:拷贝构造某类型容器 …...