【算法一周目】滑动窗口(1)

目录

长度最小的子数组

解题思路

代码实现

无重复字符的最大字串

解题思路

代码实现

最大连续1的个数l l l

解题思路

代码实现

将x减到0的最小操作数

解题思路

代码实现


长度最小的子数组

题目链接:209. 长度最小的子数组
题目描述:
给定一个含有 n 个正整数数组 nums 和一个正整数 target
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0

解题思路

解法一:暴力求解

枚举所有可能的子数组,计算子数组的和,检查是否大于等于 target ,找到符合题目要求的长度最小的子数组。

​
​
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        int ret = INT_MAX;
        
        for (int left = 0; left < n; ++left) {
            int sum = 0;
            for (int right = left; right < n; ++right) {
                sum += nums[right];
                if (sum >= target) {
                    ret = min(ret, right - left + 1);
                    break;
                }
            }
        }
        return ret == INT_MAX ? 0 : ret;
    }
};

​

​

暴力解法简单粗暴,但是由于时间复杂度是 O(n ^ 2),一旦数据量比较大,必定会超时

解法二:滑动窗口

滑动窗口其实也是基于暴力解法优化而来,滑动窗口的核心就是想办法让暴力解法中的 right 指针不回退,一直往前走

我们想想这样一个问题,在暴力解法中,当left和right找到一个合法的子数组后,left++,right有必要回退到left位置吗?答案是没有必要的,当left++后left和right区间的子数组的和可能大于等于target,也可能小于target。我们可以让left一直++,并在此过程中记录区间长度,直到left和right区间的子数组的和小于target,然后再让right++,增大区间长度的和,重复上述过程,直到遍历完数组。

滑动窗口具体过程如下:

  • 1.初始化left和right指针为0。
  • 2.进窗口:计算区间的和
  • 3.判断
  • 当区间和大于等于target时,找到合法区间,更新结果出窗口:让left++,重复判断-更新结果过程,直到区间和小于target;
  • 当区间和小于target时,进窗口:让right++,计算区间和。
  • 4.重复上述过程,直到right遍历完数组

值得注意的是,更新结果这步不是固定的,有时候在判断时更新,有时候在判断完后再更新。

代码实现

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        
        int sum = 0, n = nums.size(), len = INT_MAX;
        for(int left = 0, right = 0; right < n; right++)
        {
            sum += nums[right];
            while(sum >= target)
            {
                len = min(len, right - left + 1);
                sum -= nums[left++];
            }
        }
        return len == INT_MAX ? 0 : len;
    }
};

细节:由于求的是长度最小的子数组,所以len要初始化为INT_MAX,不能初始化为0。

时间复杂度:O(n)

空间复杂度:O(1)

无重复字符的最大字串

题目链接:3. 无重复字符的最长子串
题目描述
给定一个字符串 s,请你找出其中不含有重复字符的最长子串的长度

解题思路

解法一:暴力求解

​​​通过枚举从每个位置开始,向后寻找无重复字符的子串能到达的位置,记录其中最长的子串长度即可。在寻找无重复子串时,可以使用哈希表统计字符出现的频次,遇到重复字符时停止。​​​​

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int ret = 0;  // 记录结果
        int n = s.length();
        
        // 枚举从不同位置开始的无重复子串
        for (int i = 0; i < n; i++) {
            int hash[128] = { 0 };  // 记录字符频次
            for (int j = i; j < n; j++) {
                hash[s[j]]++;  // 统计字符频次
                if (hash[s[j]] > 1)  // 出现重复,终止
                    break;
                ret = max(ret, j - i + 1);  // 更新结果
            }
        }
        return ret;
    }
};

暴力求解的问题还是时间复杂度是O(n),对于处理数据量比较大的数据时会超时。

解法二:滑动窗口

使用滑动窗口,使得窗口内的字符不重复。

当窗口右端进入新字符时,更新哈希表记录字符频次:

  • 如果字符频次大于1,则窗口出现重复字符,开始从左侧收缩窗口直到字符频次变为1,更新结果
  • 如果没有超过1,说明没有重复字符,直接更新结果

代码实现

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int hash[128] = { 0 };  // 使用数组模拟哈希表
        int left = 0, right = 0, n = s.size(), len = 0;
        while(right < n)
        {
            hash[s[right]]++;  // 将右端字符加入窗口
            while(hash[s[right]] > 1)  //判断
                hash[s[left++]]--;      //出窗⼝
            //更新结果
            len = max(len, right - left + 1); 
            //让下⼀个元素进⼊窗⼝
            right++;    
        }
        return len;
    }
};

细节:由于s由英文字母、数字、符号和空格组成,不必真的使用unordered_map,用一个128大小的数组当作哈希表即可。

时间复杂度:O(n)

空间复杂度:O(1)

最大连续1的个数l l l

题目链接:1004. 最大连续 1 的个数 III
题目描述
给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个0,则返回数组中连续 1的最大个数。

解题思路

根据题目描述,我们可以将其转换为求一段最长的连续子区间其中0的数量不超过k个,我们用滑动窗口解决。

  • 1.初始化左右指针left和right,以及记录0个数的变量cnt。
  • 2.当right向右遍历数组时:
  • 如果当前元素是0,cnt++
  • 然后判断cnt是否大于cnt大于则让left++缩减窗口移除窗口中的0直到cnt小于等于k。
  • 3。此时窗口合法更新结果。

代码实现

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int ret = 0, cnt = 0, n = nums.size();
        for(int left = 0, right = 0; right < n; right++)
        {
            if(nums[right] == 0) cnt++; //当前元素为0,cnt++
            
            //当cnt > k时,移除窗口中的0,直到cnt <= k
            while(cnt > k)
            {
                if(nums[left] == 0)
                    cnt--;
                left++;    
            }
            //更新结果
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

时间复杂度:O(n)

空间复杂度:O(1)

将x减到0的最小操作数

题目链接:1658. 将 x 减到 0 的最小操作数

题目描述:
给你一个整数数组 nums一个整数 x每次操作时,你可以移除数组 nums 的最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,你需要修改数组以供接下来的操作使用。如果可以将 x 恰好减到 0返回最少的操作数;否则,返回 -1

解题思路

解法:滑动窗口

题目要求的是在数组左端、右端找两段连续且和为x的短数组,我们可以将其转换为在数组中找到和为 sum - x 的最长子数组,其剩余数组长度就是最小操作数,可以使用滑动窗口解决问题。

具体过程如下:

  • 1.计算数组的和 sum ,然后求出target = sum - x。这里有个小细节,若target < 0说明x > sum不可能找到题目要求的最小操作数直接返回-1
  • 2.初始化 left 和 righ t两个指针为0,再用一个变量 part_sum 记录区间长度的和。
  • 3.当 part_sum > target 时减小 part_sum,left++直到 part_sum <= target
  • 4.如果 part_sum == target更新最长子数组的长度
  • 5.right++,增大 part_sum。
  • 循环上述过程,直到 right 遍历完数组。

代码实现

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        //1.计算数组总和
        int n = nums.size(), sum = 0;
        for(auto e : nums) sum += e;

        int len = -1, target = sum - x, part_sum = 0;
        if(target < 0) return -1;
        
        //2.使用滑动窗口求出符合条件的最大子数组和
        for(int left = 0, right = 0; right < n; right++)
        {
            part_sum += nums[right];
            while(left < n && part_sum > target)
                part_sum -= nums[left++];
            if(part_sum == target)
                len = max(len, right - left + 1);
        }

        return len == -1 ? -1 : n - len;
    }
};

拜拜,下期再见😏

摸鱼ing😴✨🎞

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Methode Electronics EDI 需求分析

Methode Electronics 是一家总部位于美国的全球性技术公司&#xff0c;专注于设计和制造用于多个行业的电子和电气组件&#xff0c;产品涵盖汽车、工业、电信、医疗设备以及消费电子等多个领域&#xff0c;提供创新的解决方案。 填写Methode_EDI_Parameters_Template Methode_…

【K8S系列】Kubernetes集群资源管理与调度 深度分析

在现代微服务架构中&#xff0c;Kubernetes&#xff08;K8s&#xff09;作为容器编排平台&#xff0c;提供了强大的资源管理和调度能力。然而&#xff0c;随着应用规模的扩大和复杂性增加&#xff0c;如何高效地管理和调度集群资源成为一个关键挑战。本文将深入探讨 Kubernetes…

HarmonyOS鸿蒙系统上File文件常用操作

HarmonyOS鸿蒙系统上&#xff0c;file文件常用操作记录 1.创建文件 createFile(fileName: string, content: string): string {// 获取应用文件路径let context getContext(this) as common.UIAbilityContext;let filesDirPath context.filesDir / fileName;// 新建并打开…

【SpringMVC - 1】基本介绍+快速入门+图文解析SpringMVC执行流程

目录 1.Spring MVC的基本介绍 2.大致分析SpringMVC工作流程 3.SpringMVC的快速入门 首先大家先自行配置一个Tomcat 文件的配置 配置 WEB-INF/web.xml 创建web/login.jsp 创建com.ygd.web.UserServlet控制类 创建src下的applicationContext.xml文件 重点的注意事项和说明…

DTH11传感器温度湿度+esp8266+阿里云+小程序

arduino在之前灯的基础上再添加两个库 Adafruit_Sensor&#xff0c;#include “DHT.h” 代码如下 #include <ESP8266WiFi.h> // 引入Arduino ESP8266核心库 #include <ArduinoJson.h> // 引入JSON处理库 #include <Ticker.h> // 引入定时库 #inclu…

【汇编语言】转移指令的原理(三) —— 汇编跳转指南:jcxz、loop与位移的深度解读

文章目录 前言1. jcxz 指令1.1 什么是jcxz指令1.2 如何操作 2. loop 指令2.1 什么是loop指令2.2 如何操作 3. 根据位移进行转移的意义3.1 为什么&#xff1f;3.2 举例说明 4. 编译器对转移位移超界的检测结语 前言 &#x1f4cc; 汇编语言是很多相关课程&#xff08;如数据结构…

mac安装appuim

要在macOS上安装Appium&#xff0c;这是一个自动化测试框架&#xff0c;可以用来对移动应用进行测试&#xff08;支持iOS和Android应用&#xff09;。为了安装Appium和其依赖的环境&#xff0c;你需要做一些准备工作。以下是详细的安装步骤&#xff1a; 前提条件 1、macOS系统…

【WSL+Kali】进行系统升级时在 Setting up libc6:amd64 (2.37-15) ... 卡住不动

问题描述 当尝试执行以下命令进行系统升级时&#xff1a; sudo apt upgrade升级进程在以下步骤中卡住不动&#xff1a; Setting up libc6:amd64 (2.37-15) ...重启系统后&#xff0c;该问题仍然存在&#xff0c;如下图所示&#xff1a; 原因分析 apt命令是一个用于处理包的…

DevOps工程技术价值流:加速业务价值流的落地实践与深度赋能

DevOps的兴起&#xff0c;得益于敏捷软件开发的普及与IT基础设施代码化管理的革新。敏捷宣言虽已解决了研发流程中的诸多挑战&#xff0c;但代码开发仅是漫长价值链的一环&#xff0c;开发前后的诸多问题仍亟待解决。与此同时&#xff0c;虚拟化和云计算技术的飞跃&#xff0c;…

微深节能 平板小车运动监测与控制系统 格雷母线

微深节能的平板小车运动监测与控制系统中的格雷母线&#xff0c;是一种高精度、非接触式的位移测量系统&#xff0c;在平板小车的运动监测与控制中发挥着核心作用。 一、系统组成 该系统主要由以下关键部件组成&#xff1a; 地面电气柜&#xff1a;包含地址jie码器等重要组件&a…

【Linux课程学习】:对操作系统(Operator System)的理解

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux课程学习 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 操作系统&#xff08;Operator system&#xf…

使用Cursor和Claude AI打造你的第一个App

大家好&#xff0c;使用Cursor和Claude AI打造应用程序是一个结合智能代码辅助和人工智能对话的创新过程。Cursor是一个编程辅助工具&#xff0c;它通过智能代码补全、聊天式AI对话和代码生成等功能&#xff0c;帮助开发者提高编程效率。Claude AI则是一个强大的人工智能平台&a…

创建springboot+vue项目相关配置问题

安装并配置jdk23 在官网下载jdk Java Downloads | Oracle 中国 下载完成后双击即可安装。 安装完成后配置环境变量 此电脑->右键->属性->高级系统设置 然后一直点击确定即可。 键盘上win r java -version 可以验证是否配置成功 下载并配置maven 在官网下…

React 中使用 Axios 进行 HTTP 请求

下面是一个案例&#xff0c;展示如何在 React 中使用 Axios 进行 HTTP 请求&#xff0c;包括 GET 和 POST 请求的使用。 1. 安装 Axios 确保项目中已安装 Axios&#xff0c;可以通过以下命令安装&#xff1a; npm install axios2. 创建一个简单的 React 应用 项目结构&…

Wekan看板安装部署与使用介绍

Wekan看板安装部署与使用介绍 1. Wekan简介 ​ Wekan 是一个开源的看板式项目管理工具&#xff0c;它的配置相对简单&#xff0c;因为大多数功能都是开箱即用的。它允许用户以卡片的形式组织和跟踪任务&#xff0c;非常适合敏捷开发和日常任务管理。Wekan 的核心功能包括看板…

推荐几个 VSCode 流程图工具

Visual Studio Code&#xff08;简称VSCode&#xff09;是一个由微软开发的免费、开源的代码编辑器。 VSCode 发布于 2015 年&#xff0c;而且很快就成为开发者社区中广受欢迎的开发工具。 VSCode 可用于 Windows、macOS 和 Linux 等操作系统。 VSCode 拥有一个庞大的扩展市…

OpenHands:开源AI编程工具的新贵,让编程更自然

&#x1f680; AI技术在编程领域的应用正迅速发展&#xff0c;其中OpenHands作为一款新兴的开源AI编程工具&#xff0c;以其出色的性能和自然语言编程体验&#xff0c;成为了开发者的新宠。今天&#xff0c;让我们一起探索OpenHands的核心功能、架构设计&#xff0c;以及如何通…

C++:探索AVL树旋转的奥秘

文章目录 前言 AVL树为什么要旋转&#xff1f;一、插入一个值的大概过程1. 插入一个值的大致过程2. 平衡因子更新原则3. 旋转处理的目的 二、左单旋1. 左单旋旋转方式总处理图2. 左单旋具体会遇到的情况3. 左单旋代码总结 三、右单旋1. 右单旋旋转方式总处理图2. 右单旋具体会遇…

嵌入式硬件实战基础篇(三)-四层板PCB设计-步进电机驱动(TMC2208/TMC2209)

引言&#xff1a;我们在嵌入式硬件杂谈&#xff08;三&#xff09;中有提到阻抗匹配的问题&#xff0c;也引入了高速PCB设计的思想&#xff0c;并且此篇实战基础篇主要是基础的四层板的绘制设计&#xff0c;后续实战会对高速板展开&#xff0c;本篇主要是提升读者的设计PCB板的…

数据库基础(MySQL)

1. 数据库基础 1.1 什么是数据库 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件保存数据有以下几个缺点&#xff1a; 文件的安全性问题文件不利于数据查询和管理文件不利于存储海量数据文件在程序中控制不方便 数据库存储介质&#xff1a; 磁盘内存 为…