《LeetCode热题100》---<4.子串篇三道>
本篇博客讲解LeetCode热题100道子串篇中的三道题
第一道:和为 K 的子数组
第二道:滑动窗口最大值
第三道:最小覆盖子串
第一道:和为 K 的子数组(中等)
法一:暴力枚举
class Solution {public int subarraySum(int[] nums, int target) {int count = 0;for (int start = 0; start < nums.length; ++start) {int sum = 0;for (int end = start; end >= 0; --end) {sum += nums[end];if (sum == target) {count++;}}}return count;}
}
思想比较简单,找到所有子数组的和,如果等于目标值target。那么count++
最终返回count
法二:前缀和 + 哈希表优化
class Solution {public int subarraySum(int[] nums, int target) {int count = 0, pre = 0;HashMap < Integer, Integer > map = new HashMap < > ();map.put(0, 1);for (int i = 0; i < nums.length; i++) {pre += nums[i];if (map.containsKey(pre - target)) {count += map.get(pre - target);}map.put(pre, map.getOrDefault(pre, 0) + 1);}return count;}
}
前缀和:是求解子数组的和等问题的好方法。通过累加数组中的值,使其减去数组中某个值来得到子数组的和。
前缀和用法示例:
建哈希表优化后。
前缀和: 使用pre += nums[i]; 用pre变量来累加前缀和。只需要pre即可。
因为我们只需要用累加和减去目标值target。再去哈希表中找有没有对应的值。
如果有对应的值,说明存在子数组的和为target。那么count++
最终返回conunt
第二道:滑动窗口最大值(困难)
法一:优先队列
class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length;PriorityQueue<int[]> pQueue = new PriorityQueue<int[]>(new Comparator<int[]>() {public int compare(int[] pair1, int[] pair2) {return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1];}});for (int i = 0; i < k; ++i) {pQueue.offer(new int[]{nums[i], i});}int[] ans = new int[n - k + 1];ans[0] = pQueue.peek()[0];for (int i = k; i < n; ++i) {pQueue.offer(new int[]{nums[i], i});while (pQueue.peek()[1] <= i - k) {pQueue.poll();}ans[i - k + 1] = pQueue.peek()[0];}return ans;}
}
- 定义一个优先队列(最大堆)
pQueue
,用于存储滑动窗口内的元素。队列按照元素值降序排列,如果值相同则按索引降序排列。- 初始化队列,将数组前
k
个元素加入队列。- 创建结果数组
ans
,用于存储每个窗口的最大值。- 将队列顶部(最大值)的元素值存入结果数组的第一个位置。
- 从第
k
个元素开始,逐步将元素加入队列,并移除不在当前滑动窗口内的元素(根据索引判断)。- 每次移动窗口后,将当前窗口的最大值(队列顶部元素值)存入结果数组相应位置。
- 最终返回结果数组。
使用优先队列高效地计算了数组中每个滑动窗口的最大值。
法二:单调队列(单调性的双端队列)
单调队列套路
- 入(元素进入队尾,同时维护队列单调性)
- 出(元素离开队首)
- 记录/维护答案(根据队首)
class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length;Deque<Integer> deque = new LinkedList<Integer>();for (int i = 0; i < k; ++i) {while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {deque.pollLast();}deque.offerLast(i);}int[] ans = new int[n - k + 1];ans[0] = nums[deque.peekFirst()];for (int i = k; i < n; ++i) {while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {deque.pollLast();}deque.offerLast(i);while (deque.peekFirst() <= i - k) {deque.pollFirst();}ans[i - k + 1] = nums[deque.peekFirst()];}return ans;}
}
- 初始化一个双端队列,用于存储数组元素的索引。
- 遍历数组前
k
个元素,保持队列中元素对应的数组值按降序排列,并存储这些元素的索引。- 初始化结果数组
ans
并将第一个窗口的最大值(队列头部的元素)存入ans
的第一个位置。- 遍历数组剩余元素:
- 将新的元素索引加入队列,并移除队列中所有比当前元素小的元素的索引。
- 移除队列中不在当前窗口范围内的索引。
- 将当前窗口的最大值(队列头部的元素)存入
ans
的相应位置。最终返回结果数组
ans
。
法三:分块 + 预处理
class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length;int[] prefixMax = new int[n];int[] suffixMax = new int[n];for (int i = 0; i < n; ++i) {if (i % k == 0) {prefixMax[i] = nums[i];}else {prefixMax[i] = Math.max(prefixMax[i - 1], nums[i]);}}for (int i = n - 1; i >= 0; --i) {if (i == n - 1 || (i + 1) % k == 0) {suffixMax[i] = nums[i];} else {suffixMax[i] = Math.max(suffixMax[i + 1], nums[i]);}}int[] ans = new int[n - k + 1];for (int i = 0; i <= n - k; ++i) {ans[i] = Math.max(suffixMax[i], prefixMax[i + k - 1]);}return ans;}
}
初始化前缀最大值和后缀最大值数组:
prefixMax[i]
表示从块的开始到索引i
的最大值。suffixMax[i]
表示从索引i
到块的结束的最大值。构建前缀最大值数组:
- 遍历数组,如果索引
i
是块的开始,prefixMax[i]
等于nums[i]
。- 否则,
prefixMax[i]
等于prefixMax[i - 1]
和nums[i]
的最大值。构建后缀最大值数组:
- 从数组末尾遍历,如果索引
i
是块的结束,suffixMax[i]
等于nums[i]
。- 否则,
suffixMax[i]
等于suffixMax[i + 1]
和nums[i]
的最大值。计算每个滑动窗口的最大值:
- 遍历
ans
数组,每个窗口的最大值是suffixMax[i]
和prefixMax[i + k - 1]
的最大值。返回结果数组:
- 返回存有每个滑动窗口最大值的结果数组
ans
第三道:最小覆盖子串(困难)
方法一:滑动窗口
class Solution {Map<Character, Integer> ori = new HashMap<Character, Integer>();Map<Character, Integer> cnt = new HashMap<Character, Integer>();public String minWindow(String s, String t) {int tLen = t.length();for (int i = 0; i < tLen; i++) {char c = t.charAt(i);ori.put(c, ori.getOrDefault(c, 0) + 1);}int l = 0, r = -1;int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;int sLen = s.length();while (r < sLen) {++r;if (r < sLen && ori.containsKey(s.charAt(r))) {cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);}while (check() && l <= r) {if (r - l + 1 < len) {len = r - l + 1;ansL = l;ansR = l + len;}if (ori.containsKey(s.charAt(l))) {cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);}++l;}}return ansL == -1 ? "" : s.substring(ansL, ansR);}public boolean check() {Iterator iter = ori.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); Character key = (Character) entry.getKey(); Integer val = (Integer) entry.getValue(); if (cnt.getOrDefault(key, 0) < val) {return false;}} return true;}
}
初始化哈希表:
- 使用
ori
哈希表记录字符串t
中每个字符出现的次数。- 使用
cnt
哈希表记录当前窗口中每个字符的出现次数。滑动窗口的初始化:
- 初始化左指针
l
和右指针r
,分别表示当前窗口的左右边界。- 初始化记录最小窗口长度的
len
和最小窗口的起始和结束位置ansL
和ansR
。滑动窗口扩展:
- 移动右指针扩展窗口,若当前字符在
t
中,将其加入cnt
。缩小窗口:
- 当窗口内包含了
t
中所有字符时,尝试缩小窗口:
- 如果当前窗口长度小于已记录的最小窗口长度,更新最小窗口的位置和长度。
- 移动左指针,若左指针指向的字符在
t
中,将其从cnt
中移除。返回结果:
- 如果找到了符合条件的窗口,返回最小窗口的子字符串,否则返回空字符串。
辅助方法
check
:
- 检查当前窗口是否包含
t
中所有字符,即cnt
中每个字符的数量是否都不小于ori
中对应的数量。
相关文章:

《LeetCode热题100》---<4.子串篇三道>
本篇博客讲解LeetCode热题100道子串篇中的三道题 第一道:和为 K 的子数组 第二道:滑动窗口最大值 第三道:最小覆盖子串 第一道:和为 K 的子数组(中等) 法一:暴力枚举 class Solution {public in…...

全国区块链职业技能大赛样题第9套前端源码
后端源码地址:https://blog.csdn.net/Qhx20040819/article/details/140746050 前端源码地址:https://blog.csdn.net/Qhx20040819/article/details/140746216 智能合约+数据库表设计:https://blog.csdn.net/Qhx20040819/article/details/140746646 登录 用户管理...
如何提高编程面试成功率:LeetCode Top 100 问题及解答解析(详细面试宝典)
以下是 LeetCode Top 100 面试必备题目及其解决方案示例。这些题目涵盖了数据结构、算法、动态规划、回溯等多种重要的面试话题。希望各位同学有所收货,早日脱离底层到达彼岸! 1. Two Sum 题目: 给定一个整数数组 nums 和一个目标值 target,…...

K-近邻和神经网络
K-近邻(K-NN, K-Nearest Neighbors) 原理 K-近邻(K-NN)是一种非参数分类和回归算法。K-NN 的主要思想是根据距离度量(如欧氏距离)找到训练数据集中与待预测样本最近的 K 个样本,并根据这 K 个…...

用EasyV全景图低成本重现真实场景,360°感受数字孪生
全景图,即借助绘画、相片、视频、三维模型等形式,通过广角的表现手段,尽可能多表现出周围的环境。避免了一般平面效果图视角单一,不能带来全方位视角的缺陷,能够全方位的展示360度球型范围内的所有景致,最大…...

【Golang 面试 - 进阶题】每日 3 题(九)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/UWz06 📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏…...

孟德尔随机化、R语言,报错,如何解决?
🏆本文收录于《CSDN问答解惑-专业版》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收…...

一文剖析高可用向量数据库的本质
面对因电力故障、网络问题或人为操作失误等导致的服务中断,数据库系统高可用能够保证系统在这些情况下仍然不间断地提供服务。如果数据库系统不具备高可用性,那么系统就需要承担停机和数据丢失等重大风险,而这些风险极有可能造成用户流失&…...
JavaScript青少年简明教程:异常处理
JavaScript青少年简明教程:异常处理 在 JavaScript 中,异常指的是程序执行过程中出现的错误或异常情况。这些错误可能导致程序无法正常执行,甚至崩溃。ECMA-262规范了多种JavaScript错误类型,这些类型都继承自Error基类。主要的错…...

科普文:Lombok使用及工作原理详解
1. 概叙 Lombok是什么? Project Lombok 是一个 JAVA 库,它可以自动插入编辑器和构建工具,为您的 JAVA 锦上添花。再也不要写另一个 getter/setter 或 equals 等方法,只要有一个注注解,你的类就有一个功能齐全的生成器…...

飞致云开源社区月度动态报告(2024年7月)
自2023年6月起,中国领先的开源软件公司FIT2CLOUD飞致云以月度为单位发布《飞致云开源社区月度动态报告》,旨在向广大社区用户同步飞致云旗下系列开源软件的发展情况,以及当月主要的产品新版本发布、社区运营成果等相关信息。 飞致云开源大屏…...
mybatis-plus——实现动态字段排序,根据实体获取字段映射数据库的具体字段
前言 前端需要根据表头的点击控件可以排序,虽然前端能根据当前页的数据进行对应字段的排序,但也仅局限于实现当前页的排序,无法满足全部数据的排序,所以需要走接口的查询进行排序,获取最全的排序数据 实现方案 前端…...

redis:Linux安装redis,redis常用的数据类型及相关命令
1. 什么是NoSQL nosql[not only sql]不仅仅是sql。所有非关系型数据库的统称。除去关系型数据库之外的都是非关系数据库。 1.1为什么使用NoSQL NoSQL数据库相较于传统关系型数据库具有灵活性、可扩展性和高性能等优势,适合处理非结构化和半结构化数据,…...

JavaScript 和 HTML5 Canvas实现图像绘制与处理
前言 JavaScript 和 HTML5 的 canvas 元素提供了强大的图形和图像处理功能,使得开发者能够在网页上创建动态和交互式的视觉体验。这里我们将探讨如何使用 canvas 和 JavaScript 来处理图像加载,并在其上进行图像绘制。我们将实现一个简单的示例…...

Java之Java基础二十(集合[上])
Java 集合框架可以分为两条大的支线: ①、Collection,主要由 List、Set、Queue 组成: List 代表有序、可重复的集合,典型代表就是封装了动态数组的 ArrayList 和封装了链表的 LinkedList;Set 代表无序、不可重复的集…...

【C++BFS】1162. 地图分析
本文涉及知识点 CBFS算法 LeetCode1162. 地图分析 你现在手里有一份大小为 n x n 的 网格 grid,上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地。 请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距…...

实战:安装ElasticSearch 和常用操作命令
概叙 科普文:深入理解ElasticSearch体系结构-CSDN博客 Elasticsearch各版本比较 ElasticSearch 单点安装 1 创建普通用户 #1 创建普通用户名,密码 [roothlink1 lyz]# useradd lyz [roothlink1 lyz]# passwd lyz#2 然后 关闭xshell 重新登录 ip 地址…...

React-Native 宝藏库大揭秘:精选开源项目与实战代码解析
1. 引言 1.1 React-Native 简介 React-Native 是由 Facebook 开发的一个开源框架,它允许开发者使用 JavaScript 和 React 的编程模型来构建跨平台的移动应用。React-Native 的核心理念是“Learn Once, Write Anywhere”,即学习一次 React 的编程模型&am…...

数据结构:二叉树(链式结构)
文章目录 1. 二叉树的链式结构2. 二叉树的创建和实现相关功能2.1 创建二叉树2.2 二叉树的前,中,后序遍历2.2.1 前序遍历2.2.2 中序遍历2.2.3 后序遍历 2.3 二叉树节点个数2.4 二叉树叶子结点个数2.5 二叉树第k层结点个数2.6 二叉树的深度/高度2.7 二叉树…...

召唤生命,阻止轻生——《生命门外》
本书的目的,就是阻止自杀!拉回那些深陷在这样的思维当中正在挣扎犹豫的人,提醒他们珍爱生命,让更多的人,尤其是年轻人从执迷不悟的犹豫徘徊中幡然醒悟,回归正常的生活。 网络上抱孩子跳桥轻生的母亲&#…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...

恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...

聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...

小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...

Qwen系列之Qwen3解读:最强开源模型的细节拆解
文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...