LeetCode 热题 100 题解(二):双指针部分(2)| 滑动窗口部分(1)
题目四:接雨水(No. 43)
题目链接:https://leetcode.cn/problems/trapping-rain-water/description/?envType=study-plan-v2&envId=top-100-liked
难度:困难
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
提示:
n == height.length1 <= n <= 2 * 1040 <= height[i] <= 105
题解
首先来观察对于一个格子来说,它的容量是多少:

比如上图中的红色部分,它存储水的容量其实就是 左边的最大高度 和 右边的最大高度 的 最小值,减去这里的格子高度(案例中为 0),在上面的案例中,左边的最高高度为 2,右边的最高高度为 3。
所以本题的暴力解法就比较好想了,找到其左边最大高度,再找到其右边的最大高度,通过上面的规律进行运算。
class Solution {public int trap(int[] height) {int res = 0;for (int i = 1; i < height.length; i++) {int left = i - 1;int right = i + 1;int maxLeft = 0;int maxRight = 0;while (left >= 0) { // 去左边寻找最大的maxLeft = Math.max(maxLeft, height[left--]);}while (right < height.length) { // 去右边寻找最大的maxRight = Math.max(maxRight, height[right++]);}int temp = Math.min(maxLeft, maxRight) - height[i]; // 执行运算逻辑res += temp > 0 ? temp : 0;}return res;}
}
这个方法的时间复杂度无疑是非常高的,因为每遍历到一个节点的时候都需要遍历整张表,接下来考虑如何对上面的方法进行优化。
首先来看左边的最大值,考虑一下,我们真的有必要每次去遍历来求得最大值吗?
可以将之前遍历过的节点的最大值保存下来,比如说这么一个高度数组 4,2,0,3,2,5 ,我们从第二个数字开始遍历,当执行完这个数字的逻辑之后,就可以拿它和之前的最大高度作比较,用作下一个节点的左边最大高度,这样不断更新就能保证每次求得的都是准确的。
class Solution {public int trap(int[] height) {int res = 0;int maxLeft = height[0];for (int i = 1; i < height.length; i++) {int left = i - 1;int right = i + 1;int maxRight = 0;while (right < height.length) { // 找到右边最大高度maxRight = Math.max(maxRight, height[right++]);}int temp = Math.min(maxLeft, maxRight) - height[i];res += temp > 0 ? temp : 0;maxLeft = Math.max(height[i], maxLeft); // 维护一个更新的 maxLeft}return res;}
}
既然对左边可以进行优化,那对右边是否可以优化呢?
因为是从前向后遍历的,所以右边肯定不可能像左边这样简单的更新;所以可以考虑提前处理,如果从后向前遍历的话,就可以类似左边那样求出 每个节点 的右最大值,所以可以在进入循环之前,先遍历一次高度数组,求出一个存储着每个节点右最大值的数组。
class Solution {public int trap(int[] height) {int res = 0;int maxLeft = height[0];int k = 2;int[] maxRight = new int[height.length];int m = height[maxRight.length - 1];for (int j = maxRight.length - 2; j >= 0; j--) { // 从后向前遍历,维护一个存储每个节点最大值的数组maxRight[j] = m;m = Math.max(m, height[j]);}for (int i = 1; i < height.length; i++) {int temp = Math.min(maxLeft, maxRight[i]) - height[i]; // 使用数组中的值res += temp > 0 ? temp : 0;maxLeft = Math.max(height[i], maxLeft);}return res;}
}
题目一:无重复字符的最长字串(No. 3)
题目链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/?envType=study-plan-v2&envId=top-100-liked
题目难度:中等
给定一个字符串 s ,请你找出其中不含有重复字符的 最长
子串
的长度。
示例 1:
输入:s = "abcabcbb"
输出:3
解释: 因为无重复字符的最长子串是"abc",所以其长度为 3。
示例 2:
输入:s = "bbbbb"
输出:1
解释:因为无重复字符的最长子串是"b",所以其长度为 1。
示例 3:
输入:s = "pwwkew"
输出:3
解释:因为无重复字符的最长子串是"wke",所以其长度为 3。请注意,你的答案必须是子串的长度,"pwke" 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104s由英文字母、数字、符号和空格组成
题解
首先来看第一种方法,提到最长子串,想到的第一个方法就是动态规划。
先来尝试找一下状态,题目中问的是没有重复字符的最长的子串,可以将某个节点的状态定义为:以这个节点为结尾的,不含有重复字符的字串的最大长度,这种方式在处理子串的问题中非常常见。
再来思考这个状态应该如何转移。对于一个节点其实有这些选择
- 从这个节点开始(重新开始)
- 接续前面的子串
本题接续前面子串的时候要考虑不能含有重复的元素,所以并不像之前的题目那样就简单的做一个加一,但总而言之状态是可以转移的,那就来尝试一下。
先来确定 dp 数组,根据上面的推理,dp 数组只需要一维就即可, dp[i] 的含义为以 s.charAt(i) 为结尾的,不含有重复子串的最大长度。
然后就是确定状态转移方程了,对于一个下标为 x 的节点,它所代表的子串就是从 x - dp[i] 到 x 这个范围内内容;比如我们现在遍历到了下标为 x + 1 的节点,如果想要接续上前面的内容,就需要上面的范围中不含有 s.charAt(x + 1) 这个字符,此时需要通过遍历来确定是否有这个字符。
如果没有发现,那 dp[i] = dp[i - 1] + 1
如果发现了重复的字符串,比如下面的情况

此时要求得的是绿色的 b 的值,前一个节点最大子串的长度为 3,但当遍历到图中粉色的节点的时候发现了重复,此时 b 的长度应该为多少呢?是 2
画个图来更直观的了解一下:

当发现了相同的节点之后,这个值应该就是从被发现的位置索引 + 1 一直到新节点的长度
此时就确定了两种情况的递推公式,下面来讨论一下初始化
因为需要前一个节点的情况,所以 dp[0] 是要被初始化的,按照上面的含义,该位置应该被初始化为 1。
class Solution {public int lengthOfLongestSubstring(String s) {if (s.length() == 0) return 0;int[] dp = new int[s.length()];dp[0] = 1;int res = 1;for (int i = 1; i < s.length(); i++) {int field = dp[i - 1]; // 需要查询重复的范围char c = s.charAt(i);boolean findSame = false; // 是否找到了相同的节点while (field > 0) {int index = i - (field--);if (s.charAt(index) == c) { // 找到了相同的节点int m = i - index - 1 + 1;dp[i] = m;findSame = true;break;}}if (!findSame) dp[i] = dp[i - 1] + 1;res = Math.max(dp[i], res); // 动态更新 res}return res;}
}
接下来来看一下滑动窗口方案
所谓的滑动窗口其实就是用索引去限定一个范围,通过不断移动左范围和右范围的方式来调整窗口的范围,从而收集信息。
当滑动窗口的内容满足要求的时候就不断 移动右边界,来扩展滑动窗口的大小,如果发现不满足要求,也就是出现了重复的情况,就通过 收缩左边界 最终使得窗口内的元素始终满足要求,然后记录滑动窗口的长度。
滑动窗口方法的核心和上面的动态规划方法相同,都是通过遍历每个元素为 右节点 的情况,来不断更新最大值。
class Solution {char[] charArray;public int lengthOfLongestSubstring(String s) {if (s.length() == 0) return 0;charArray = s.toCharArray();int left = 0, right; // 左范围,右范围int res = 1;for (int i = 1; i < charArray.length; i++) {right = i;while (examine(left, right, charArray[i])) {left++;}res = Math.max(right - left + 1, res); // 更新结果}return res;}// 检测范围内是否有和此时右范围相同的元素public boolean examine(int left, int right, char c) {for (int i = left; i <= right - 1; i++) {if (charArray[i] == c) return true;}return false;}
}
相关文章:
LeetCode 热题 100 题解(二):双指针部分(2)| 滑动窗口部分(1)
题目四:接雨水(No. 43) 题目链接:https://leetcode.cn/problems/trapping-rain-water/description/?envTypestudy-plan-v2&envIdtop-100-liked 难度:困难 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&am…...
常用的深度学习自动标注软件
0. 简介 自动标注软件是一个非常节省人力资源的操作,而随着深度学习的发展,这些自动化标定软件也越来越多。本文章将会着重介绍其中比较经典的自动标注软件 1. AutoLabelImg AutoLabelImg 除了labelimg的初始功能外,额外包含十多种辅助标注…...
选择程序员是为什么?
本章节是关于为什么会选择一名程序员的经验分享 首先,我为什么会选择这个方向,可能是因为钱多,学东西不就是为了赚钱嘛?这是一点,不过最让我接收这个行业的是好奇世界的新大陆,可以简单的说就是,…...
线程池参数如何设置
线程池参数设置 hello丫,各位小伙伴们,好久不见了! 下面,我们先来复习一下线程池的参数 1、线程池参数有哪些? corePoolSize(核心线程数):线程池中的常驻核心线程数。即使这些线程…...
qt环境搭建-镜像源安装Qt Creator(5.15.2)以及配置环境变量
前言: 版本:5.15.2 镜像源:ustc与清华 纯小白,找了半天的镜像源安装qtcreator,搞了半天结果安装的是最新的,太新的对小白很不友好,bug比较多,支持的系统也不全,口碑不…...
SQL Server详细安装使用教程
1.安装环境 现阶段基本不用SQL Server数据库了,看到有这样的分析话题,就把多年前的存货发一下,大家也可以讨论看看,思路上希望还有价值。 SQL Server 2008 R2有32位版本和64位版本,32位版本可以安装在Windows XP及以上…...
深度解读C++17中的std::string_view:解锁字符串处理的新境界
深入研究C17中的std::string_view:解锁字符串处理的新境界 一、简介二、std::string_view的基础知识2.1、构造函数2.2、成员函数 三、std::string_view为什么性能高?四、std::string_view的使用陷阱五、std::string_view源码解析六、总结 一、简介 C中有…...
汇编基础-----常见命令基本使用
汇编基础-----常见命令基本使用 MOV:将数据从一个位置复制到另一个位置。 MOV destination, source例如: MOV RAX, RBX ; 将RBX寄存器中的值复制到RAX寄存器中ADD/SUB:将两个操作数相加或相减。 ADD destination, source SUB destinatio…...
科研学习|可视化——相关性结果的可视化
一、相关性分析介绍 相关性分析是指研究两种或者两种以上的变量之间相关关系的统计分析方法,一般分析步骤为: 1)判断变量间是否存在关联;2)分析关联关系(线性/非线性)、关联方向(正相…...
MapReduce过程解析
一、Map过程解析 Read阶段:MapTask通过用户编写的RecordReader,从输入的InputSplit中解析出一个个key/value。Map阶段:将解析出的key/value交给用户编写的Map()函数处理,并产生一系列的key/value。Collect阶段:在用户编…...
速看!这8道嵌入式面试题你都会吗?
大家好,我是知微! 正逢求职季,分享一些嵌入式面试当中经常会遇到的题目,希望这些干货对小伙伴们面试有用哦! 1、介绍一下static关键字的作用 在C语言中,static 关键字有几种不同的作用,根据其…...
基于SSM的电影网站(有报告)。Javaee项目。ssm项目。
演示视频: 基于SSM的电影网站(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,通过Spring SpringMv…...
SOCKS代理是如何提高网络性能和兼容性的?
SOCKS代理作为一种网络协议中间件,不仅在提升网络隐私和安全性方面发挥着重要作用,也在提高网络性能和兼容性方面有着不容忽视的影响🚀。本文将深入探讨SOCKS代理如何通过减少网络延迟🚀、优化数据传输🔄、提高跨平台兼…...
好菜每回味道不同--建造者模式
1.1 炒菜没放盐 中餐,老板需要每次炒菜,每次炒出来的味道都有可能不同。麦当劳、肯德基这些不过百年的洋快餐却能在有千年饮食文化的中国发展的那么好呢?是因为你不管何时何地在哪里吃味道都一样,而鱼香肉丝在我们中餐却可以吃出上…...
RuoYi-Cloud下载与运行
一、源码下载 若依官网:RuoYi 若依官方网站 鼠标放到"源码地址"上,点击"RuoYi-Cloud 微服务版"。 跳转至Gitee页面,点击"克隆/下载",复制HTTPS链接即可。 源码地址为:https://gitee.com/y_project/RuoYi-Cloud.git 点击复制 打开IDEA,选…...
Vue2.x计算属性
1.计算属性 在Vue 插值表达式内实现一些操作其实非常便利,但如果表达式的逻辑过于复杂,会让插值过于臃肿且难以维护。这时可以考虑使用Vue的计算属性 1.1 不使用计算属性的例子 <!DOCTYPE html> <html><head><meta charset"…...
Vue中使用require.context()自动引入组件和自动生成路由的方法介绍
目录 一、自动引入组件 1、语法 2、使用 2.1、在compoents文件下随便创建index.js文件 2.2、mian.js引入该js 二、自动生成路由 1、示例: 2、使用 2.1、在router文件下随便创建autoRouter.js文件 2.2、在router文件下index.js文件中引入autoRouter.js文件…...
【炒股Zero To Hero】MACD金叉死叉到底是否有效,加上这个指标回报率增加197倍
移动平均收敛散度(MACD - Moving Average Convergence Divergence)是一种趋势跟踪动量指标,显示了证券价格的两个移动平均之间的关系。它用于识别趋势的方向和强度,属于技术分析中振荡器的一类。 MACD如何衡量股票及其趋势 有两…...
Linux网络名称空间和虚拟机有何区别
在Linux系统中,网络名称空间和虚拟机都是实现资源隔离和虚拟化的技术,但它们在设计理念、实现机制、资源消耗、使用场景等方面存在着显著的区别。本文旨在全方位、系统性地分析这两种技术的区别。🔍 1. 设计理念与实现机制 1.1. 网络名称空…...
【UE Niagara】蓝图获取粒子数据
目录 效果 步骤 一、创建粒子 二、创建蓝图接收Niagara参数 效果 步骤 一、创建粒子 1. 新建一个Niagara发射器,使用Empty模板,打开后先添加“Spawn Rate”模块,这里设置粒子生成速率为0.7 在“Initialize Particle”模块中设置粒子颜色…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
