首页 > 编程语言 >【Java完整版 面试必备】Leetcode Top100题目和答案-子串篇

【Java完整版 面试必备】Leetcode Top100题目和答案-子串篇

时间:2024-07-02 11:56:22浏览次数:3  
标签:deque Java nums int 数组 字符 窗口 完整版 Top100

以下摘自leetcode Top100精选题目-子串篇

560. 和为 K 的子数组

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 

子数组是数组中元素的连续非空序列。

示例:

示例 1:

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

Solution:

public int subarraySum(int[] nums, int k) {
    Map<Integer, Integer> prefixSumCount = new HashMap<>();
    prefixSumCount.put(0, 1); // 前缀和为0的次数初始化为1,代表空子数组
    int currentSum = 0;
    int result = 0;

    for (int num : nums) {
        currentSum += num;
        // 查找是否存在前缀和为 currentSum - k 的子数组
        if (prefixSumCount.containsKey(currentSum - k)) {
            result += prefixSumCount.get(currentSum - k);
        }
        // 更新前缀和的计数
        prefixSumCount.put(currentSum, prefixSumCount.getOrDefault(currentSum, 0) + 1);
    }

    return result;
}

  1. 初始化一个哈希表 prefixSumCount,用来存储前缀和出现的次数,初始时前缀和为0的出现次数为1(表示空子数组的和)。
  2. 初始化一个变量 currentSum 来累计当前的前缀和。
  3. 遍历数组 nums,对于每个元素,将其加到 currentSum 上,并查看 currentSum - k 是否在 prefixSumCount 中。如果在,说明从某个前缀和到当前位置的和为 k,因此将其对应的计数加到结果中。
  4. 将 currentSum 在 prefixSumCount 中的计数加1,表示当前的前缀和出现了一次。
  5. 遍历结束后,结果就是和为 k 的子数组的数量。

239. 滑动窗口最大值

给你一个整数数组 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

Solution:

可以使用双端队列(Deque)来高效解决。双端队列可以在两端进行插入和删除操作,非常适合用来维护一个动态调整的窗口(滑动窗口)

import java.util.Deque;
import java.util.LinkedList;

public class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return new int[0];
        }
        
        Deque<Integer> deque = new LinkedList<>(); // 双端队列,存储数组索引
        int[] result = new int[nums.length - k + 1]; // 存储结果的最大值
        
        // 处理第一个窗口
        for (int i = 0; i < k; i++) {
            // 清除deque中不在窗口范围内的索引,并保证deque的前端是最大值的索引
            while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                deque.pollLast();
            }
            deque.offerLast(i);
        }
        
        // 处理剩余窗口
        for (int i = k; i < nums.length; i++) {
            // 记录当前窗口的最大值
            result[i - k] = nums[deque.peekFirst()];
            
            // 清除deque中已经不在窗口范围的索引
            while (!deque.isEmpty() && deque.peekFirst() <= i - k) {
                deque.pollFirst();
            }
            
            // 维护deque,确保最大值的索引在前端
            while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                deque.pollLast();
            }
            deque.offerLast(i);
        }
        
        // 记录最后一个窗口的最大值
        result[nums.length - k] = nums[deque.peekFirst()];
        
        return result;
    }
}

     先初始化一个双端队列deque来存储数组中最大值的索引,以及一个结果数组result来存放每个窗口的最大值。算法分为两个阶段:初始化第一个窗口和滑动窗口更新。在初始化阶段,通过比较将最大值的索引存入队列。随着窗口向右滑动,不断地从队列头部移除不在窗口内的索引,并根据新进入窗口的元素更新队列,确保队列前端始终指向当前窗口内的最大值索引。将每个窗口的最大值依次存入结果数组并返回。

76. 最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

注意:

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例:

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

Solution:

public class Solution {
    public String minWindow(String s, String t) {
        if (s.length() == 0 || t.length() == 0) {
            return "";
        }
        
        // 记录目标字符串t中每个字符需要的个数
        int[] targetCharCount = new int[128];
        for (char c : t.toCharArray()) {
            targetCharCount[c]++;
        }
        
        // 左右指针定义窗口的边界
        int left = 0, right = 0;
        // 记录符合条件的最小窗口的起始索引及长度
        int start = 0, minLen = Integer.MAX_VALUE;
        // 当前窗口内各个字符的数量
        int formed = 0;
        
        // 当右指针未越界时循环
        while (right < s.length()) {
            char c = s.charAt(right);
            // 如果目标字符串需要当前字符,则更新formed计数
            if (targetCharCount[c] > 0) {
                formed++;
            }
            // 更新当前字符在窗口中的计数
            targetCharCount[c]--;
            right++;
            
            // 当窗口内的字符已经符合要求时,尝试缩小窗口
            while (formed == t.length()) {
                if (right - left < minLen) {
                    start = left;
                    minLen = right - left;
                }
                
                char leftChar = s.charAt(left);
                // 恢复左指针指向字符的计数
                targetCharCount[leftChar]++;
                // 如果恢复计数后,该字符的计数大于0,说明它不再是我们所需要的字符了
                if (targetCharCount[leftChar] > 0) {
                    formed--;
                }
                left++;
            }
        }
        
        // 如果minLen仍为初始值,说明没有符合条件的子串
        return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
    }
}

     先通过一个数组targetCharCount记录目标字符串t中每个字符的需求量。使用两个指针leftright定义一个滑动窗口,并通过变量formed来追踪窗口内是否已经包含了t中的所有字符。当窗口内的字符组合满足条件时,尝试收缩窗口左边界以寻找最小覆盖子串。在循环过程中,不断更新最小覆盖子串的起始索引和长度。如果找到符合条件的子串,则返回该子串;否则,返回空字符串。

标签:deque,Java,nums,int,数组,字符,窗口,完整版,Top100
From: https://blog.csdn.net/weixin_43298211/article/details/140100580

相关文章

  • IntelliJ IDEA java maven项目读取配置文件信息 java.util.ResourceBundle 方式
    一、在main目录下新建resources目录并将其设为资源文件目录  创建config.properties文件二、在pom.xml中添加下面代码 只这样打包后jar才能有配置文件<resources><resource><filtering>true</filtering><directory>src/main/......
  • CH01_初识JavaScript
    第1章:初识JavaScript编程语言本章目标了解为什么要学习JavaScipt编程语言掌握JS的基本结构掌握JS的执行原理掌握JS的基本语法结构掌握JS的几种输出方式掌握JS的注释课程回顾什么是HTML?HTML的标签分为块级元素和行级元素,他们的区别是什么?HTML的表单元素有那些?HTML的列表......
  • java 查询日期月末、季末、年末,上月末、上季末、上年末,以及两个日期是否是同一月,同一
    packagecom.dc.galaxydata.model;importcom.dc.common.util.DateUtil;importjava.util.Calendar;importjava.util.Date;publicclassDateLastEndUtil{publicstaticvoidmain(String[]args){//System.out.println(DateUtil.format(lastMonthEn......
  • java 查询日期列表月末对应上月末,季度末对应上季度末,年末对应上年末,取列表月度,季度,年
    packagecom.dc.galaxydata.model;importcom.dc.common.util.DateUtil;importjava.util.ArrayList;importjava.util.Date;publicclassEndDates{publicstaticvoidmain(String[]args){ArrayList<Date>dateList=newArrayList<>(......
  • JavaWeb名词解释及帮助文档
    Web前端开发web标准:大部分网页标准由W3C万维网联盟制定,由HTML、CSS、JavaScript组成HTML:HyperTextMarkupLanguage超文本标记语言(负责网页的结构--页面元素和内容)CSS:CascadingStyleSheet层叠样式表(负责网页的表现--页面元素的外观、位置等页面样式)JavaScript:JS,一门跨平台......
  • Java开发者LLM实战——使用LangChain4j构建本地RAG系统
    1、引言由于目前比较火的chatGPT是预训练模型,而训练一个大模型是需要较长时间(参数越多学习时间越长,保守估计一般是几个月,不差钱的可以多用点GPU缩短这个时间),这就导致了它所学习的知识不会是最新的,最新的chatGPT-4o只能基于2023年6月之前的数据进行回答,距离目前已经快一年的时间,如......
  • Java 并发 - ThreadLocal详解
    ThreadLocal是通过线程隔离的方式防止任务在共享资源上产生冲突,线程本地存储是一种自动化机制,可以为使用相同变量的每个不同线程都创建不同的存储。@立刀旁目录#带着BAT大厂的面试问题去理解#ThreadLocal简介#ThreadLocal理解#ThreadLocal原理#如何实现线程隔......
  • 秋招Java后端开发冲刺——基础篇5(String&集合)
    一、StringString类是Java中字符串操作类,位于java.lang包下String类型对象的底层使用字符数组char[]存储字符串,由final修饰且没有提供公共的修改方法,因此String对象是不可变的。常见方法方法名作用trim()去掉字符串首尾空字符split(分隔符/正则表达式)分割字符串substring......
  • 基于java+springboot+vue实现的家政服务平台(文末源码+Lw)299
    摘 要现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本家政服务平台就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达......
  • 基于java+springboot+vue实现的旅游管理系统(文末源码+Lw)227
    摘 要现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本旅游管理系统就是在这样的大环境下诞生,其可以帮助使用者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达......