《LeetCode热题100》---<4.子串篇三道>

news2024/11/15 12:19:11

本篇博客讲解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;
    }
}
  1. 定义一个优先队列(最大堆)pQueue,用于存储滑动窗口内的元素。队列按照元素值降序排列,如果值相同则按索引降序排列。
  2. 初始化队列,将数组前 k 个元素加入队列。
  3. 创建结果数组 ans,用于存储每个窗口的最大值。
  4. 将队列顶部(最大值)的元素值存入结果数组的第一个位置。
  5. 从第 k 个元素开始,逐步将元素加入队列,并移除不在当前滑动窗口内的元素(根据索引判断)。
  6. 每次移动窗口后,将当前窗口的最大值(队列顶部元素值)存入结果数组相应位置。
  7. 最终返回结果数组。

 使用优先队列高效地计算了数组中每个滑动窗口的最大值。

 法二:单调队列(单调性的双端队列)

单调队列套路

  • 入(元素进入队尾,同时维护队列单调性)
  • 出(元素离开队首)
  • 记录/维护答案(根据队首)
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;
    }
}
  1. 初始化一个双端队列,用于存储数组元素的索引。
  2. 遍历数组前 k 个元素,保持队列中元素对应的数组值按降序排列,并存储这些元素的索引。
  3. 初始化结果数组 ans 并将第一个窗口的最大值(队列头部的元素)存入 ans 的第一个位置。
  4. 遍历数组剩余元素:
  • 将新的元素索引加入队列,并移除队列中所有比当前元素小的元素的索引。
  • 移除队列中不在当前窗口范围内的索引。
  • 将当前窗口的最大值(队列头部的元素)存入 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 和最小窗口的起始和结束位置 ansLansR
  • 滑动窗口扩展

    • 移动右指针扩展窗口,若当前字符在 t 中,将其加入 cnt
  • 缩小窗口

    • 当窗口内包含了 t 中所有字符时,尝试缩小窗口:
      • 如果当前窗口长度小于已记录的最小窗口长度,更新最小窗口的位置和长度。
      • 移动左指针,若左指针指向的字符在 t 中,将其从 cnt 中移除。
  • 返回结果

    • 如果找到了符合条件的窗口,返回最小窗口的子字符串,否则返回空字符串。
  • 辅助方法 check

    • 检查当前窗口是否包含 t 中所有字符,即 cnt 中每个字符的数量是否都不小于 ori 中对应的数量。

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

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

相关文章

C语言进阶 13. 文件

C语言进阶 13. 文件 文章目录 C语言进阶 13. 文件13.1. 格式化输入输出13.2. 文件输入输出13.3. 二进制文件13.4. 按位运算13.5. 移位运算13.6. 位运算例子13.7. 位段 13.1. 格式化输入输出 格式化输入输出: printf %[flags][width][.prec][hlL]type scanf %[flags]type %[fl…

yolo格式数据集之空中及地面拍摄道路病害检测7种数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用

yolo格式数据集之空中及地面拍摄道路病害检测7种数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用 本数据为空中及地面拍摄道路病害检测检测数据集&#xff0c;数据集数量如下&#xff1a; 总共有:33585张 训练集&#xff1a;6798张 验证集&#xff1a;3284张 测试集&a…

视频监控国标GB28181平台EasyGBS如何更换默认的SQLite数据库?

视频流媒体安防监控国标GB28181平台EasyGBS视频能力丰富&#xff0c;部署灵活&#xff0c;既能作为业务平台使用&#xff0c;也能作为安防监控视频能力层被业务管理平台调用。国标GB28181视频EasyGBS平台可提供流媒体接入、处理、转发等服务&#xff0c;支持内网、公网的安防视…

数据集相关类代码回顾理解 | np.mean\transforms.Normalize\transforms.Compose\xxx.transform

数据集相关类代码回顾理解 | StratifiedShuffleSplit\transforms.ToTensor\Counter 目录 np.mean transforms.Normalize transforms.Compose xxx.transform np.mean meanRGB[np.mean(x.numpy(),axis(1,2)) for x,_ in train_ds] 计算每个样本的&#xff08;RGB&#xff0…

鸿蒙应用框架开发【JS注入与执行】 Web

JS注入与执行 介绍 本示例基于H5游戏&#xff0c;通过arkui的button实现对游戏实现基本控制&#xff0c;展示webview的JS注入与执行能力&#xff0c;及native应用与H5的通信能力。 效果预览 使用说明 1.设备连接热点&#xff0c;可访问互联网。 2.打开应用&#xff0c;通过…

【Java】如何避免超预期的高并发压力压垮系统?

一、问题解析 在互联网高可用架构设计中&#xff0c;限流是一种经典的高可用架构模式。因为某些原因&#xff0c;大量用户突然访问我们的系统时&#xff0c;或者有黑客恶意用DoS&#xff08;Denial of Service&#xff0c;拒绝服务&#xff09;方式攻击我们的系统时&#xff0…

oracle表、表空间使用空间

文章目录 一、Oracle查询表空间占用情况二、Oracle查询表占用的空间三、Oracle查询表空间使用情况四、Oracle查询每张表占用空间五、表空间大小 TOC 一、Oracle查询表空间占用情况 oracle日常工作中查看表占用空间大小是数据库管理中的基本操作&#xff1a; SELECT a.tablesp…

大龄程序员转型攻略:拥抱人工智能,开启新征程

前言 随着科技的飞速发展&#xff0c;人工智能浪潮席卷全球&#xff0c;相关岗位炙手可热。在这个背景下&#xff0c;许多大龄程序员开始思考如何转型&#xff0c;以适应时代的变化。结合自身编程基础&#xff0c;大龄程序员可以学习机器学习、深度学习算法&#xff0c;投身于…

MySQL 高性能索引使用策略

文章目录 前置知识表准备一. 不在索引列上使用任何操作二. 联合索引字段列全值匹配三. 最佳左前缀法则四. 范围条件放最后五. 覆盖索引使用六. 不等于导致索引失效七. is null/not null 影响八. like 查询的使用九. 字符类型加引号十. OR关键字前后索引问题十一. 利用索引来做排…

昇思25天学习打卡营第XX天|Pix2Pix实现图像转换

Pix2Pix是一种基于条件生成对抗网络&#xff08;cGAN&#xff09;的图像转换模型&#xff0c;由Isola等人在2017年提出。它能够实现多种图像到图像的转换任务&#xff0c;如从草图到彩色图像、从白天到夜晚的场景变换等。与传统专用机器学习方法不同&#xff0c;Pix2Pix提供了一…

【Dart 教程系列第 49 篇】什么是策略设计模式?如何在 Dart 中使用策略设计模式

这是【Dart 教程系列第 49 篇】&#xff0c;如果觉得有用的话&#xff0c;欢迎关注专栏。 博文当前所用 Flutter SDK&#xff1a;3.22.1、Dart SDK&#xff1a;3.4.1 文章目录 一&#xff1a;什么是策略设计模式&#xff1f;二&#xff1a;为什么要使用策略设计模式&#xff1…

pytest框架的作用--面试

在做接口自动化的时候我们经常会用到pytest这个框架&#xff0c;这个框架有哪些优点 1. 帮我们找到用例 模块名必须以test_开头&#xff1b;类名必须以Test开头&#xff0c;并且不能有init方法&#xff1b;用例方法必须以test开头 2.执行用例 有很多参数设置执行 3. 断言-可以…

大数据-51 Redis 高可用方案CAP-AP 主从复制 一主一从 全量和增量同步 哨兵模式 docker-compose测试

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

昇思25天学习打卡营第XX天|07-函数式自动微分

本章分为两类&#xff0c;一神经网络训练依赖反向传播算法&#xff0c;通过损失函数计算预测值与标签间的误差&#xff0c;反向传播求得梯度&#xff0c;进而更新模型参数。 二、自动微分简化了这一过程&#xff0c;将复杂运算分解为基础运算&#xff0c;隐藏了求导细节&#…

重新思考终端 LLMs 和 Agents

0x0 前言 LLM (Large Language Models) 的风头一时无两&#xff0c;席卷万千行业。业内不乏有关于 LLM 的研究和讨论&#xff0c;但鲜有立足终端的视角。团队上半年曾有过对 GPT 进终端的分析&#xff0c;但 LLM 日新月异&#xff0c;旧分析已经不完全跟得上变化了。适逢年底规…

达飞集团全新互联网投融资平台即将隆重上线

全球知名海运和物流巨头达飞集团(CMA CGM)即将推出其最新力作——全新互联网投融资平台。该平台旨在为投资者提供安全、稳定且高效的投资机会,通过筹集资金支持全球各地实体产业项目的落地建设。这一举措不仅展现了达飞集团在金融科技领域的创新能力,也彰显了其在海运和物流行业…

C# Solidworks二次开发------信息提示

一、内容 对于信息提示主要有两种方式。 方式一&#xff1a;Solidworks自带的提示 方式二&#xff1a;C#中的消息提示 二、代码 ISldWorks swApp Activator.CreateInstance(Type.GetTypeFromProgID("SldWorks.Application")) as SldWorks; swApp.NewPart(); ModelD…

懂个锤子Vue 自定义指定、插槽:

Vue自定义指定、插槽&#x1f6e0;️&#xff1a; 前言&#xff1a;当然既然学习框架的了&#xff0c;HTMLCSSJS三件套必须的就不说了&#xff1a; JavaScript 快速入门 紧跟前文&#xff0c;目标学习Vue2.0——3.0&#xff1a; 懂个锤子Vue、WebPack5.0、WebPack高级进阶 涉…

npm与webpack的学习笔记

npm 定义&#xff1a;npm是Node.js标准的软件包管理器。它起初是作为下载和管理Node.js包依赖的方式&#xff0c;但其现在也已成为前端JavaScript中使用的工具。 包 包&#xff1a;将模块、代码、其他资料聚合成一个文件夹 包的分类&#xff1a; 项目包&#xff1a;主要用…

upload-labs-靶场(1-19关详细解答 保姆级教程)

Pass-01 下载 upload-labs-mster靶场 创建一个upload目录 不然无法打开upload-labs 靶场 1.我们先上传一个 php后缀文件 显示我们该文件不允许上传 只能上传 jpg png gif的文件后缀 2.我们可以上传 自己写的php 后缀改成jpg上传 然后抓包 可以看到 数据上传了 我们可以在burps…