代码随想录 LeetCode数组篇 长度最小的子数组

news2024/11/21 0:15:55

文章目录

  • (中等)209. 长度最小的子数组
  • (中等)904. 水果成篮
  • (困难)76. 最小夫覆盖子串


(中等)209. 长度最小的子数组

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

我的思路:双指针p和q,滑动窗口的思想

每次判断从p到q的范围内的值的总和是否大于等于target

  • 如果是,那么记录p和q之间的长度,记录p和q的范围内的值的总和,并把p后移一位
  • 如果不是,则把q后移一位,扩大区间长度
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int p = 0;
        int q = 0;
        int sum = 0;
        int len = 100001;
        int n = nums.length;
        while (p < n && q < n) {
            if (sum < target) {
                sum += nums[q];
                q++;
            } else {
                len = Math.min(len, q - p);
                sum -= nums[p];
                p++;
            }
        }
        while (p < n) {
            if (sum >= target) {
                len = Math.min(len, q - p);
                sum -= nums[p];
                p++;
            } else {
                break;
            }
        }

        return len != 100001 ? len : 0;
    }
}

把代码精简一下

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        int len = 100001;
        int start = 0;
        int end = 0;
        int sum = 0;
        while (end < n) {
            sum += nums[end];
            while (sum >= target) {
                len = Math.min(len, end - start + 1);
                sum -= nums[start];
                start++;
            }
            end++;
        }
        return len != 100001 ? len : 0;
    }
}

官方提供的其他思路,暴力法

暴力法,最直观的方法。初始化子数组的最小长度为无穷大,枚举数据nums中的每个下标为子数组的开始下标,对于每个开始下标i,需要找到大于或等于i的最小下标j,使得从nums[i]到nums[j]的元素和大于等于target,并更新子数组的最小长度(此时子数组的最小长度是j-i+1)

超时

在这里插入图片描述

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        int len = 100001;
        for (int i = 0; i < n; i++) {
            int sum = 0;
            for (int j = i; j < n; j++) {
                sum += nums[j];
                if (sum >= target) {
                    len = Math.min(len, j - i + 1);
                }
            }
        }
        return len != 100001 ? len : 0;
    }
}

复杂度分析:

  • 时间复杂度:O(n^2),其中n是数组的长度。需要遍历每个下标作为子数组的开始下标,对于每个开始的下标,需要遍历其后面的下标得到长度最小的子数组。

  • 空间复杂度:O(1)

官方提供的其他思路,前缀和+二分查找

暴力法的时间复杂度是O(n^2),因为在确定每个子数组的开始下标后,找到长度最小的子数组需要O(n)的时间。如果使用二分查找,则可以将时间优化到O(logn)。

为了使用二分查找,需要额外创建一个数组sums用于存储数组nums的前缀和,其中sums[i]表示从nums[0]到nums[i-1]的元素和。得到前缀和之后,对于每个开始下标i,可通过二分查找得到大于或等于i的最小下标bound,使得sums[bound]-sums[i-1]>=target,并更新子数组的最小长度,此时子数组的长度是bound-(i-1)。

因为这道题保证了数组中每个元素都为正,所以前缀和一定是递增的,这一点保证了二分的正确性。如果题目没有说明数组中每个元素都为正,就不能使用二分来查找这个位置了。

在这里插入图片描述

import java.util.Arrays;

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        int len = 100001;
        int[] sums = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            sums[i] = sums[i - 1] + nums[i - 1];
        }

        //为了方便计算,令size=n+1
        //sums[0]=0,意味着前0个元素的前缀和为0
        //sums[1]=A[0],意味着前1个元素的前缀和为A[0]

        for (int i = 1; i <= n; i++) {
            //得到前缀和以后,对于每个开始下标i,可通过二分查找得到大于或等于i的最小下表bound
            //使得sums[bound]-sums[i-1]>=s
            int s = target + sums[i - 1];
            int bound = Arrays.binarySearch(sums, s);
            if (bound < 0) {
                bound = -bound - 1;
            }
            if (bound <= n) {
                len = Math.min(len, bound - (i - 1));
            }
        }
        return len != 100001 ? len : 0;
    }
}

复杂度分析:

  • 时间复杂度:O(nlogn),其中n是数组的长度。需要遍历每个下标作为子数组的开始下标,遍历的时间复杂度是O(n),对于每个开始下标,需要通过二分查找找到长度最小的子数组,二分查找的时间复杂度是O(logn),因此总时间复杂度是O(nlogn)
  • 空间复杂度:O(n),其中n是数组的长度。额外创建数组sums存储前缀和。

(中等)904. 水果成篮

在这里插入图片描述
在这里插入图片描述
官方题解:滑动窗口

我们可以使用滑动窗口解决本题,left和right分别表示满足要求的窗口的左右边界,同时我们使用哈希表存储这个窗口内的数及出现的次数。

我们每次将right移动一个位置,并将fruits[right]加入哈希表。如果,此时哈希表不满足要求(即哈希表中出现超过两个键值对),那么我们需要不断移动left,需要将fruit[left]对应的值减1,当值减少到0时,就需要将fruit[left]为键的元素从哈希表中移除,直到哈希表满足要求为止。

在这里插入图片描述

import java.util.HashMap;

class Solution {
    public int totalFruit(int[] fruits) {
        HashMap<Integer, Integer> map = new HashMap<>();
        int n = fruits.length;

        int left = 0;
        int right = 0;
        int ans = 0;
        while (right < n) {
            map.put(fruits[right], map.getOrDefault(fruits[right], 0) + 1);
            while (map.size() > 2) {
                map.put(fruits[left], map.get(fruits[left]) - 1);
                if (map.get(fruits[left]) == 0) {
                    map.remove(fruits[left]);
                }
                left++;
            }
            ans = Math.max(ans, right - left + 1);
            right++;
        }
        return ans;
    }
}

其他思路,也是滑动窗口,使用数组

初始化一个数组,记录每个元素出现的次数

用一个变量来记录当前区间中有几种不同的数字,如果超过两种,则需要移动j(靠左边的指针),来缩小当前窗口,使得窗口中的元素满足题目条件

在这里插入图片描述

class Solution {
    public int totalFruit(int[] fruits) {
        int n = fruits.length;
        int[] nums = new int[n];
        int total = 0;
        int i = 0;
        int j = 0;
        int ans = 0;
        while (i < n) {
            nums[fruits[i]]++;
            if (nums[fruits[i]] == 1) {
                total++;
            }
            while (total > 2) {
                nums[fruits[j]]--;
                if (nums[fruits[j]] == 0) {
                    total--;
                }
                j++;
            }
            ans = Math.max(ans, i - j + 1);
            i++;
        }
        return ans;
    }
}

(困难)76. 最小夫覆盖子串

在这里插入图片描述
在这里插入图片描述
官方思路

本题要求返回字符串s中包含的字符串t的全部字符的最小出窗口,称包含t的全部字母的窗口为【可行窗口】

使用滑动窗口思想解决这个问题。在滑动窗口类型的问题中,都会包含两个指针,一个用于【延伸】现有窗口的r指针,另一个用于【收缩】窗口的l指针。在任一时刻,只有一个指针在运动,而另一个保持静止。

在s上滑动窗口,通过移动r指针不断扩张窗口,当窗口包含t全部所需的字符后,如果能收缩,我们就收缩窗口直到最小的窗口。

下面的代码是,根据上面的思路,自己写的,因为题目中说明了字符串由英文字母组成,所以用两个长度为52的数组分别记录,在字符串s和t中每个字符出现的次数。前26位存储小写字母出现的次数,后26位存储大写字母出现的次数。

首先,统计字符串t中每个字符出现的次数。
然后遍历字符串s,check()函数用来检验当前left到right的区间内的字符是否已经覆盖了字符串t,就是比较当arrt数组不为零的那些位置,arrs数组中的元素是否大于等于arrt数组中的那些位置,如果相等,则覆盖字符串t。

import java.util.Arrays;

class Solution {
    public String minWindow(String s, String t) {

        if (s.length() < t.length()) {
            return "";
        }

        int[] arrt = new int[52];
        for (char c : t.toCharArray()) {
            if (c >= 'a' && c <= 'z') {
                arrt[c - 'a']++;
            } else {
                arrt[c - 'A' + 26]++;
            }
        }

        int[] arrs = new int[52];
        int left = 0;
        int right = 0;
        int l = -1;
        int r = -1;
        int n = s.length();
        int ans = 100001;
        while (right < n) {
            char rc = s.charAt(right);
            if (rc >= 'a' && rc <= 'z') {
                arrs[rc - 'a']++;
            } else {
                arrs[rc - 'A' + 26]++;
            }
            while (left <= right && check(arrs, arrt)) {
                if (right - left + 1 < ans) {
                    ans = right - left + 1;
                    l = left;
                    r = right;
                }
                char lc = s.charAt(left);
                if (lc >= 'a' && lc <= 'z') {
                    arrs[lc - 'a']--;
                } else {
                    arrs[lc - 'A' + 26]--;
                }
                left++;
            }
            right++;
        }
        return (l == -1 && r == -1) ? "" : s.substring(l, r + 1);
    }

    public boolean check(int[] arrs, int[] arrt) {
        for (int i = 0; i < 52; i++) {
            if (arrt[i] != 0) {
                if (arrs[i] < arrt[i]) {
                    return false;
                }
            }
        }
        return true;
    }
}

下面是官方代码

在这里插入图片描述

import java.util.HashMap;
import java.util.Map;

class Solution {

    //记录字符串t中每个字符出现的次数
    HashMap<Character, Integer> ori = new HashMap<>();

    //记录left到right区间内,字符出现的次数
    HashMap<Character, Integer> cnt = new HashMap<>();

    public String minWindow(String s, String t) {

        int tLen = t.length();
        int sLen = s.length();

        if (tLen > sLen) {
            return "";
        }

        for (char c : t.toCharArray()) {
            ori.put(c, ori.getOrDefault(c, 0) + 1);
        }

        //不断移动的left和right
        int l = 0;
        int r = 0;

        //left,right区间长度
        int len = 100001;

        //记录当前最优的left和right
        int ansL = -1;
        int ansR = -1;

        while (r < sLen) {
            if (ori.containsKey(s.charAt(r))) {
                cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
            }
            while (l <= r && check()) {
                if (r - l + 1 < len) {
                    ansL = l;
                    ansR = r;
                    len = Math.min(len, r - l + 1);
                }
                if (ori.containsKey(s.charAt(l))) {
                    cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);
                }
                l++;
            }
            r++;
        }
        return ansL == -1 ? "" : s.substring(ansL, ansR + 1);
    }

    public boolean check() {
        for (Map.Entry<Character, Integer> entry : ori.entrySet()) {
            Character key = entry.getKey();
            Integer value = entry.getValue();
            if (cnt.getOrDefault(key, 0) < value) {
                return false;
            }
        }
        return true;
    }
}

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

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

相关文章

牛客练习赛111 D青蛙兔子的约会

题目链接 示例1 输入 3 3 4 10 1 2 2 4 5 1 1 3 5 11 1 1 输出 YES NO NO 说明 第一问&#xff0c;青蛙晚上向右跳1次&#xff0c;白天无法与兔子相遇。青蛙向右跳2次&#xff0c;也就是2a6的距离&#xff0c;白天兔子向左跳1次&#xff0c;可以相遇。所以在跳[1,2]次中&#…

app持续交付实战

app持续交付实战 一、学习目标二、优势三、子任务拆分四、环境依赖1、安卓 SDK2、安卓设备&#xff08;真机 or 模拟器&#xff09;3、Appium 自动化测试4、JDK5、Python3环境6、allure-commandline工具7、allure插件 五、实战任务&#xff1a;串行执行 Jenkins Pipeline 项目1…

Python学习之批量转换图片格式和统一图片尺寸

前言 大家在工作的时候是不是都会接触到很多的图片&#xff0c;为了满足不同的需求&#xff1a; 兼容性&#xff1a;不同设备和应用程序可能支持不同的图片格式。通过转换图片格式&#xff0c;可以确保在各种设备和应用程序中都能够正确地显示图片。 文件大小&#xff1a;不…

基于matlab 从接收脉冲中提取波形参数

一、前言 现代飞机通常随身携带雷达警告接收器 &#xff08;RWR&#xff09;。RWR检测到雷达发射&#xff0c;并在雷达信号照射到飞机上时警告飞行员。RWR不仅可以检测雷达发射&#xff0c;还可以分析截获的信号并编目信号来自哪种雷达。此示例显示了 RWR 如何估计截获脉冲的参…

10倍速度开发贪吃蛇游戏之AI辅助

今天就来聊聊AI代码辅助神器&#xff0c;即便是零基础也能上手&#xff0c;因为实在是太强了&#xff0c;这以后叫程序员们怎么活啊&#xff01;话不多说&#xff0c;直接上神器 我用的是cursor,其实目前AI辅助代码不止cursor&#xff0c;还有微软家的copilot X这个根植于gith…

JVM-01-JVM知识

1-JVM内存模型 Java开发人员一般情况下&#xff0c;使用过程中&#xff0c;不用关注内存的申请和释放&#xff0c;得益于JVM自动内存分配机制&#xff0c;但是其实是个双刃剑&#xff0c;这可以提升Java开发的效率&#xff0c;但是弱化了开发人员内存管理意识&#xff0c;系统容…

四元数快速入门【Quaternion】

四元数&#xff08;Quaternion&#xff09;是用于旋转和拉伸向量的数学运算符。 本文提供了一个概述&#xff0c;以帮助理解在空间导航等应用程序中对四元数的需求。 推荐&#xff1a;用 NSDT场景设计器 快速搭建3D场景。 可以通过多种方式在空间中准确定位、移动和旋转物体。 …

U盘在电脑上读不出来怎么办?详细解决方法在这!

案例&#xff1a;u盘在电脑上读不出来 【不知道为什么&#xff0c;我把u盘插入电脑后电脑完全读不出。我也不知道到底哪里出现了问题&#xff0c;有人可以帮我解答一下吗&#xff1f;】 U盘作为我们生活中经常使用的存储工具&#xff0c;其能帮我们存储大量的文件&#xff0c…

BM54-三数之和

题目 给出一个有n个元素的数组S&#xff0c;S中是否有元素a,b,c满足abc0&#xff1f;找出数组S中所有满足条件的三元组。 数据范围&#xff1a;0≤n≤1000&#xff0c;数组中各个元素值满足 ∣val∣≤100。 空间复杂度&#xff1a;O(n^2)&#xff0c;时间复杂度 O(n^2)。 注…

React 第三方插件 —— Cron 表达式生成器(qnn-react-cron)

qnn-react-cron 可以看做 react-cron-antd 的升级版&#xff08;具体“渊源”可见文档&#xff09;&#xff0c;现有功能如下&#xff1a; &#x1f389; 全面支持 cron&#xff1a;秒、分、时、日、月、周、年 &#x1f389; 日及周条件互斥&#xff0c;自动改变响应值 &…

8年测试开发,写给1-3年功能测试的几点建议,满满硬货指导

从15年毕业到现在也从业八年了&#xff0c;普通本科毕业&#xff0c;现在一家互联网公司担任测试部门总监&#xff0c;摸爬打滚&#xff0c;坑坑洼洼也经历了不少。思绪很久决定还是写下这篇&#xff0c;希望对后进的小伙子少走一点弯路。 很多人把职场想得太美好&#xff0c;其…

学node写接口!!!

fs 可以读取文档 fs.readFild() 用于读取文件 第一个参数 路径 第二个参数 "utf8"(默认值) 第三个参数 函数 function(err , dataStr ){ 第一个参数是错误&#xff0c; 第二个参数是正确的可以拿到读取文件里面的值 } fs.writeFile() 用于创建文件添加内容 …

【LeetCode中等】1419.数青蛙

给你一个字符串 croakOfFrogs&#xff0c;它表示不同青蛙发出的蛙鸣声&#xff08;字符串 “croak” &#xff09;的组合。由于同一时间可以有多只青蛙呱呱作响&#xff0c;所以 croakOfFrogs 中会混合多个 “croak” 。 请你返回模拟字符串中所有蛙鸣所需不同青蛙的最少数目。…

如何根据参考文献查找原文及详细的文献信息

当我们已知参考文献想要查看下载原文以及相关信息时可以用下面的方法&#xff1a; 例如这篇参考文献&#xff1a;Alsamhi S H, Almalki F, Ma O, et al. Predictive estimation of optimal signal strength from drones over IoT frameworks in smart cities[J]. IEEE Transac…

FPGA实现SDI视频解码PCIE传输 提供工程源码和QT上位机源码加技术支持

目录 1、前言2、我已有的SDI编解码方案3、我已有的PCIE方案4、总体设计思路和方案SDI摄像头Gv8601a单端转差GTX解串SDI解码VGA时序恢复YUV转RGB图像缓存PCIE发送通路SDI同步输出通路 5、vivado工程详解6、驱动安装7、QT上位机软件8、上板调试验证SDI同步HDMI输出验证PCIE输出验…

neo4j结合gds实现最短路径算法

背景&#xff1a;Neo4j自带的cypher语句中的 shortestpath allShortestPaths 返回值内容非常有限&#xff0c;不易处理, 在实际生产环境中可用性极低&#xff0c; 且若带where条件查询时&#xff0c;查询效率极低 因此&#xff0c;使用Neo4j自带的插件如apoc来进行最短路径查询…

使用@Autowired、@Qualifier、@Primary注解自动装配组件

1.Autowired、Qualifier、Primary注解 1.1.Autowired注解 Autowired注解可以对类成员变量、方法和构造函数进行标注&#xff0c;完成自动装配的工作。 package org.springframework.beans.factory.annotation;import java.lang.annotation.Documented; import java.lang.ann…

hexo stellar主题添加运行时间-利用不蒜子

在网站的页脚想添加博客运行的时间以及&#xff0c;查了一下资料&#xff0c;根据下面的这个博主的代码进行了修改。 打造一个舒服的写作环境&#xff08;Hexo&#xff09; 下面我们开始修改&#xff1a; stellar/layout/_partial/main/footer.ejs 找到//footer的 这一段 // …

基于logback 实现springboot的日志配置

目录 一、前言 二、使用详解 2.1、打印到文件中 2.2、打印级别控制 2.3、logback 详细配置 2.4、logback 配置文件的组成 2.4.1、<root>标签 2.4.2、<contextName>标签 2.4.3、<property>标签 2.4.4、<appender>标签 2.4.5、<logger&g…

Mysql索引(2):索引结构

1 概述 MySQL的索引是在存储引擎层实现的&#xff0c;不同的存储引擎有不同的索引结构&#xff0c;主要包含以下几种&#xff1a; 索引结构描述BTree索最常见的索引类型&#xff0c;大部分引擎都支持 B 树索引 Hash索引 底层数据结构是用哈希表实现的, 只有精确匹配索引列的…