LeetCode HOT100(四)字串

news/2024/9/11 3:41:35/ 标签: leetcode, 算法, 职场和发展

leetcode.cn/problems/subarray-sum-equals-k/?envType=study-plan-v2&envId=top-100-liked" rel="nofollow">和为 K 的子数组(mid)

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
子数组是数组中元素的连续非空序列。

输入:nums = [1,1,1], k = 2
输出:2


解法1:前缀和+Map
这是一道经典的前缀和运用题。
统计以每一个 nums[i] 为结尾,和为 k 的子数组数量即是答案。
我们可以预处理前缀和数组 prefix,对于求解以某一个 nums[i] 为结尾的,和为 k 的子数组数量,本质上是求解在 [0,i] 中,prefix 数组中有多少个值为 prefix[i]−k 的数,这可以在遍历过程中使用「哈希表」进行同步记录。
是以当前节点为结尾的计算,不是以当前节点为起始的计算!!!

public int subarraySum(int[] nums, int k) {int len = nums.length;int[] prefix = new int[len];prefix[0] = nums[0];for (int i=1; i<len; i++){prefix[i] = prefix[i-1]+nums[i];}Map<Integer,Integer> map = new HashMap<>();//当子串的起始节点为0,即取前缀和的整段而不做截断//需要插入一个长度为0的子串map.put(0,1);int res = 0;for(int i=0; i<len; i++){res += map.getOrDefault(prefix[i]-k,0);map.put(prefix[i],map.getOrDefault(prefix[i],0)+1);}return res;
}

leetcode.cn/problems/sliding-window-maximum/?envType=study-plan-v2&envId=top-100-liked" rel="nofollow">滑动窗口最大值(hard)

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。

输入: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 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7


解法1:滑动窗口,最优
假设我们当前处理到某个长度为 k 的窗口,此时窗口往后滑动一格,会导致后一个数(新窗口的右端点)添加进来,同时会导致前一个数(旧窗口的左端点)移出窗口。
随着窗口的不断平移,该过程会一直发生。若同一时刻存在两个数 nums[j] 和 nums[i](j<i)所在一个窗口内,下标更大的数会被更晚移出窗口,此时如果有 nums[j]<=nums[i] 的话,可以完全确定 nums[j] 将不会成为后续任何一个窗口的最大值,此时可以将必然不会是答案的 nums[j] 从候选中进行移除
不难发现,当我们将所有必然不可能作为答案的元素(即所有满足的小于等于 nums[i] )移除后,候选集合满足「单调递减」特性,即集合首位元素为当前窗口中的最大值(为了满足窗口长度为 k 的要求,在从集合头部取答案时需要先将下标小于的等于的 i−k 的元素移除)。
为方便从尾部添加元素,从头部获取答案,我们可使用「双端队列」存储所有候选元素。
用一个容器,充当窗口,保持它存储的元素是单调非递增,这样它的第一个元素就是容器中的最大值,最后一个就是最小值,根据前面的分析,向右滑动过程中,如果遇到了更大的元素,就可以把在容器中小于它的元素都移除掉,因为后加入的更大的元素才可能成为容器中的最大值。因为第一个元素是最大值,我们需要能够获取它,所以,这是一个先入先出的容器,这里用队列就可以了。它的思路与单调栈一样,但只不过用队列来当容器,这便是“单调队列”了。

public int[] maxSlidingWindow(int[] nums, int k) {Deque<Integer> stack = new ArrayDeque<>();int[] res = new int[nums.length-k+1];for(int i=0; i<nums.length; i++){// 队列中的下标是小于新加入的i,那么如果[i]>= 队尾// 说明队尾肯定不会是窗口里的一个最大值了// 从队尾开始,把小于[i]的都移除掉。// 这样就能保证队列的值是一个单调非递减队列了while(!stack.isEmpty() && nums[stack.peekLast()]<nums[i]){stack.pollLast();}stack.addLast(i);if(i>=k-1){// 现在的队首就是窗口中的最大值res[i-k+1] = nums[stack.peekFirst()];// 再把左滑出窗口的最大值从队列中移除,因为它已被滑出窗口了if(stack.peekFirst()+k-1 == i) stack.pollFirst();}}return res;
}

解法2:优先队列
image.png

public int[] maxSlidingWindow(int[] nums, int k) {// 使用优先队列(大顶堆)来存储窗口中的索引,以便快速找到最大值PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> nums[b] - nums[a]);// 初始化结果数组,长度为 nums 数组长度减去窗口大小 k 再加 1int[] res = new int[nums.length - k + 1];for (int i = 0; i < nums.length; i++) {// 将当前索引 i 加入优先队列pq.add(i);// 当索引 i 大于 k-1 时,说明窗口已经滑动了至少 k 次,可以开始记录最大值if (i >= k - 1) {// 记录窗口内的最大值,即优先队列中索引对应的值res[i - k + 1] = nums[pq.peek()];// 清除出窗口的元素,即索引小于 i-k+1 的元素while (!pq.isEmpty() && pq.peek() <= i - k + 1) {pq.poll();}}}// 返回结果数组,包含了每个窗口的最大值return res;
}

leetcode.cn/problems/minimum-window-substring/?envType=study-plan-v2&envId=top-100-liked" rel="nofollow">最小覆盖字串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。

输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”
解释:最小覆盖子串 “BANC” 包含来自字符串 t 的 ‘A’、‘B’ 和 ‘C’。


解法1:滑动窗口

public String minWindow(String s, String t) {// 初始化一个足够大的数组来计数字符,假设字符集大小为70(A-Z的大小写)int[] cnt = new int[70];// 标记是否找到有效子串boolean flag = false;// 遍历字符串 t,对每个字符进行计数,并将对应的数组元素减1for (int i = 0; i < t.length(); i++) {char c = t.charAt(i);cnt[c - 'A']--; // 将字符转换为0-65的整数,便于在数组中索引}// 初始化结果字符串为 s,假设没有找到更小的子串String res = s;// 初始化左右指针int l = 0, r = 0;// 滑动窗口的右边界while (r < s.length()) {// 将 s 的当前字符计数加1cnt[s.charAt(r) - 'A']++;// 当前窗口包含 t 的所有字符时,尝试收缩左边界while (l <= r && check(cnt)) {// 标记已找到有效子串flag = true;// 更新最小窗口String tmp = s.substring(l, r + 1);res = tmp.length() < res.length() ? tmp : res;// 移动左边界,将 l 所指的字符从计数器中减去cnt[s.charAt(l) - 'A']--;l++;}// 扩展右边界,继续寻找可能的最小子串r++;}// 如果找到了有效子串,返回 res,否则返回空字符串return flag ? res : "";
}// 检查数组中的所有计数是否都大于等于0,即 s 的当前窗口是否包含 t 的所有字符
public boolean check(int[] arr) {for (int i = 0; i < arr.length; i++) {if (arr[i] < 0)return false; // 如果有字符计数小于0,则当前窗口不包含 t 的所有字符}return true; // 所有字符计数都非负,说明当前窗口包含 t 的所有字符
}

定义两个长度为 60(足够存下所有字母种类)的数组 c1 和 c2,用于存储字符频率。其中 c1 用于记录字符串 t 中字符的频率,c2 用于记录当前滑动窗口内字符的频率。
设定好字母与频率数组下标的映射关系:小写字母 a-z 对应下标 0-25,大写字母 A-Z 对应下标 26-51。
使用变量 tot 来记录还需要匹配的字符种类数,当 tot = 0 代表当前滑动窗口对应的子串能够实现对 t 的覆盖,即任意字符满足 c2[i]≥c1[i]。
使用双指针 j 和 i 表示滑动窗口的左右边界。从前往后遍历字符串 s,在每个位置上更新字符频率数组 c2。若 c2 中字符的频率达到了 c1 中的字符频率,则将 tot 减 1,表示一个字符已经匹配完成。
每当右边界往后移动一步之后,滑动窗口会增加一个字符。此时我们检查左边界能否右移,同时不会使得 tot 变大。即每次右边界右移后,我们检查左边界 c2[j]>c1[j] 是否满足:

  • 若满足:说明当前左边界指向字符并非必须,当前子串 s[j…i] 必然不是最短子串。我们让左边界 j 进行右移,并重复进行左边界 c2[j]>c1[j] 的检查,直到窗口不能再收缩
  • 若不满足:说明当前窗口没有任何一个后缀字符串能够实现对 t 的覆盖,我们并不能对窗口实现收缩

每次对窗口移动完成后,我们检查当前 tot 是否为 0(对字符串 t 的覆盖是否完成),若为 0 则尝试用当前窗口对应的字符串 s[j…i] 更新 ans。

class Solution {public String minWindow(String s, String t) {int n = s.length(), tot = 0;int[] c1 = new int[60], c2 = new int[60];for (char x : t.toCharArray()) {if (++c1[getIdx(x)] == 1) tot++;}String ans = "";for (int i = 0, j = 0; i < n; i++) {int idx1 = getIdx(s.charAt(i));if (++c2[idx1] == c1[idx1]) tot--;while (j < i) {int idx2 = getIdx(s.charAt(j));if (c2[idx2] > c1[idx2] && --c2[idx2] >= 0) j++;else break;}if (tot == 0 && (ans.length() == 0 || ans.length() > i - j + 1)) ans = s.substring(j, i + 1);}return ans;}int getIdx(char x) {return x >= 'A' && x <= 'Z' ? x - 'A' + 26 : x - 'a';}
}

http://www.ppmy.cn/news/1474726.html

相关文章

租用海外服务器需要考虑哪些因素

当企业选择租用海外服务器时需要考虑到哪些因素呢&#xff1f; 对于海外服务器的租用我们需要考虑到机房的位置以及服务器的稳定性如何&#xff0c;所以企业可以选择离目标用户群体比较近一点的机房&#xff0c;以此来降低服务器的延迟度并且能够提高用户的访问速度。 对于机房…

WEB07Vue+Ajax

1. Vue概述 Vue&#xff08;读音 /vjuː/, 类似于 view&#xff09;&#xff0c;是一款用于构建用户界面的渐进式的JavaScript框架&#xff08;官方网站&#xff1a;https://cn.vuejs.org&#xff09;。 在上面的这句话中呢&#xff0c;出现了三个词&#xff0c;分别是&#x…

Memcached负载均衡:揭秘高效缓存分发策略

标题&#xff1a;Memcached负载均衡&#xff1a;揭秘高效缓存分发策略 在分布式缓存系统中&#xff0c;Memcached通过负载均衡技术来提高缓存效率和系统吞吐量。负载均衡确保了缓存请求能够均匀地分配到多个缓存节点上&#xff0c;从而防止任何一个节点过载。本文将深入探讨Me…

对话大模型Prompt是否需要礼貌点?

大模型相关目录 大模型&#xff0c;包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步&#xff0c;扬帆起航。 基于Dify的QA数据集构建&#xff08;附代码&#xff09;Qwen-2-7B和GLM-4-9B&#x…

6-6 Ant.design配置(react+区块链实战)

6-6 Ant.design配置&#xff08;react区块链实战&#xff09; https://ant.design/index-cn 直接点击开始使用ant进行button等按钮的样式 https://ant.design/docs/react/use-with-create-react-app-cn 在 create-react-app 中使用 安装antd&#xff0c;在react项目woniu-pet-…

react学习——29react之useState使用

useState 是 React Hooks 中的一个重要函数&#xff0c;它用于在函数组件中添加状态。在类组件中&#xff0c;我们通常使用 this.state 和 this.setState 来管理组件的状态&#xff0c;而在函数组件中&#xff0c;我们可以使用 useState 来达到同样的目的。 1、导入 useState&…

MyBatis(35)如何在 MyBatis 中实现软删除

实现软删除在MyBatis中通常意味着更新数据库记录的某个字段&#xff0c;而不是真正地从数据库中删除记录。这个字段&#xff08;通常是is_deleted、deleted或status等&#xff09;被用来标记记录是否被删除。下面我们将详细探讨如何在MyBatis中实现软删除&#xff0c;包括数据库…

Hadoop-25 Sqoop迁移 增量数据导入 CDC 变化数据捕获 差量同步数据 触发器 快照 日志

章节内容 上节我们完成了如下的内容&#xff1a; Sqoop MySQL迁移到HiveSqoop Hive迁移数据到MySQL编写脚本进行数据导入导出测试 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机…

在分布式环境中,怎样保证 PostgreSQL 数据的一致性和完整性?

文章目录 在分布式环境中保证 PostgreSQL 数据的一致性和完整性一、数据一致性和完整性的重要性二、分布式环境对数据一致性和完整性的挑战&#xff08;一&#xff09;网络延迟和故障&#xff08;二&#xff09;并发操作&#xff08;三&#xff09;数据分区和复制 三、保证 Pos…

解读网络安全公司F5:助企业高效简化多云和应用部署

伴随企业加速数字化转型工作、扩展到新的基础设施环境并采用微服务架构&#xff0c;企业正拥抱混合和多云基础设施所带来的灵活性。Ernst & Young调查数据显示&#xff0c;84%的企业正处于向现有网络安全解决方案套件添加多种新技术的早期阶段。企业同样意识到&#xff0c;…

Perl语言之标量

Perl对于变量的定义&#xff0c;分为三种类型&#xff1a;标量、数组和哈希。   标量是 Perl 语言中最简单的一种数据类型。标量中可以存储整数、字符串、浮点数、字符等&#xff0c;数据格式不做严格区分。在使用标量时需要再变量前面加$&#xff0c;如&#xff1a; #! /us…

Chain-of-Verification Reduces Hallucination in Lagrge Language Models阅读笔记

来来来&#xff0c;继续读文章了&#xff0c;今天这个是meta的研究员们做的一个关于如何减少LLM得出幻觉信息的工作&#xff0c;23年底发表。文章链接&#xff1a;https://arxiv.org/abs/2309.11495 首先&#xff0c;这个工作所面向的LLM的问答任务&#xff0c;是list-based q…

使用Nginx实现高效负载均衡

概述 Nginx是一款高性能的HTTP和反向代理服务器&#xff0c;广泛用于Web服务的负载均衡。它能有效分发流量至多个后端服务器&#xff0c;提高网站的可用性和响应速度&#xff0c;同时增强系统的可扩展性和安全性。本文将介绍如何配置Nginx进行负载均衡&#xff0c;并提供具体的…

服务发现与注册:Eureka与Consul

在微服务架构中&#xff0c;服务发现与注册是一个非常重要的部分。通过服务发现机制&#xff0c;微服务能够相互找到并进行通信&#xff0c;而不需要了解彼此的具体地址。本文将详细介绍两种主流的服务发现与注册框架&#xff1a;Eureka和Consul&#xff0c;并提供相应的代码示…

Web开发 —— 放大镜效果(HTML、CSS、JavaScript)

目录 一、需求描述 二、实现效果 三、完整代码 四、实现过程 1、HTML 页面结构 2、CSS 元素样式 3、JavaScript动态控制 &#xff08;1&#xff09;获取元素 &#xff08;2&#xff09;控制大图和遮罩层的显隐性 &#xff08;3&#xff09;遮罩层跟随鼠标移动 &…

C# Winform 系统方案目录的管理开发

在做一个中等复杂程度项目时&#xff0c;我们通常有系统全局配置&#xff0c;还要有对应的方案目录的管理和更新。 比如我们有如下需求&#xff1a;开发一个方案管理&#xff0c;可以新建、打开和保存方案&#xff0c;同时还需要保存方案中的各种文件。我设计的采用目录管理和…

【YashanDB知识库】表收集统计信息默认阈值引起SQL执行效率差

【问题分类】性能优化 【关键字】统计信息&#xff0c;阈值&#xff0c;执行计划 【问题描述】表新增87w数据自动收集统计信息任务没有启动导致SQL执行计划变差 【问题原因分析】 CUS_REGISTER_READ 数据总量是18374074&#xff0c;插入81万&#xff0c;统计信息失效的阈值是…

流程图怎么做?有三种制作方法

流程图怎么做&#xff1f;在日常生活和工作中&#xff0c;流程图作为一种直观展示步骤、流程或决策路径的工具&#xff0c;扮演着不可或缺的角色。它不仅能够帮助我们理清思路、规划任务&#xff0c;还能促进团队协作与沟通。那么&#xff0c;如何高效地绘制流程图呢&#xff1…

Objective-C 自定义渐变色Slider

文章目录 一、前情概要二、具体实现 一、前情概要 系统提供UISlider&#xff0c;但在开发过程中经常需要自定义&#xff0c;本次需求内容是实现一个拥有渐变色的滑动条&#xff0c;且渐变色随着手指touch的位置不同改变区域&#xff0c;类似如下 可以使用CAGradientLayer实现渐…

Web开发:一个可拖拽的模态框(HTML、CSS、JavaScript)

目录 一、需求描述 二、实现效果 三、完整代码 四、实现过程 1、HTML 页面结构 2、CSS 元素样式 3、JavaScript动态控制 &#xff08;1&#xff09;获取元素 &#xff08;2&#xff09;显示\隐藏遮罩层与模态框 &#xff08;3&#xff09;实现模态框拖动效果 一、需求…