算法: 滑动窗口题目练习

文章目录

  • 滑动窗口
    • 长度最小的子数组
    • 无重复字符的最长子串
    • 最大连续1个个数 III
    • 将x减到0的最小操作数
    • 水果成篮
    • 找到字符串中所有字母异位词
    • 串联所有单词的子串
    • 最小覆盖子串
  • 总结


滑动窗口

长度最小的子数组

在这里插入图片描述
做这道题时,脑子里大概有个印象,知道要用滑动窗口,但是对于滑动窗口为什么就对,不会落情况吗?对于这一点不是很清楚.

emmm虽然独自做出来了,但是还是在怀疑滑动窗口的正确性.

class Solution {public int minSubArrayLen(int target, int[] nums) {int left = 0;int sum = 0;int min = Integer.MAX_VALUE;for(int right = 0; right < nums.length;right++) {sum += nums[right];if(sum >= target) {while(sum >= target) {sum -= nums[left++];}int tmp = right - left + 2;if(min > tmp) {min = tmp;}}}return min==Integer.MAX_VALUE?0:min;}
}

看完题解后,明白了.
在这里插入图片描述
看题解后的代码:

  • 使用了Math.min(),加快了做题速度,在比赛中可以省下时间.
  • 其他的都差不多~
class Solution {public int minSubArrayLen(int target, int[] nums) {int left = 0;int sum = 0;int min = Integer.MAX_VALUE;for(int right = 0; right < nums.length;right++) {sum += nums[right];while(sum >= target) {min = Math.min(min,right-left+1);sum -= nums[left++];}}return min==Integer.MAX_VALUE?0:min;}
}

无重复字符的最长子串

在这里插入图片描述
自己使用滑动窗口+哈希表做出来了.
最开始想只用滑动窗口解决,结果想不出来.然后就想到了hash.
刚开始写时没写对,后来画了两次图,根据图,然后就写出来了~

看题解前:

class Solution {public int lengthOfLongestSubstring(String s) {int max = 0;int n = s.length();char[] ss = s.toCharArray();boolean[] hash = new boolean[1080];int left = 0,right = 0;while (right < n) {if(!hash[ss[right]]) {hash[ss[right++]] = true;max = Math.max(max,right-left);}else {hash[ss[left++]] = false;}}return max;}
}

看题解后:

  • 我用的boolean,他用的int.都差不多吧.
  • 还有就是我的hash数组给大了.
class Solution {public int lengthOfLongestSubstring(String s) {int max = 0;int n = s.length();char[] ss = s.toCharArray();int[] hash = new int[128];int left = 0,right = 0;while (right < n) {hash[ss[right]]++;while(hash[ss[right]] > 1) {hash[ss[left++]]--;}max = Math.max(max,right-left+1);right++;}return max;}
}

最大连续1个个数 III

在这里插入图片描述
自己写的代码,能过,但是看起来不美观,效率也不够高.

class Solution {public int longestOnes(int[] nums, int k) {int left = 0, right = 0;int n = nums.length;int max = 0;while (right < n) {if (nums[right] == 1) {max = Math.max(max, right - left + 1);right++;}else{if (k > 0) {max = Math.max(max, right - left + 1);right++;k--;} else {while(nums[left]==1) {left++;}k++;left++;}}}return max;}
}

看题解:

  • emm,只能说没有对比,就没有伤害.人家写的代码又少又快~
  • 题解使用了for循环,这样可以少写几个if,比如说当nums[right]==1时,我们可以忽略,自动让right++就行;
  • 与我写的不同的是,他的k可以小于0,而我的k不能.
class Solution {public int longestOnes(int[] nums, int k) {int max = 0;for(int right = 0,left = 0;right < nums.length;right++) {if(nums[right] == 0) k--;while(k < 0) if(nums[left++] == 0) k++;max = Math.max(max,right-left+1);}return max;}
}

翻了翻题解,发现还有高手!
以下是大佬的题解.
难理解的地方在于为啥能直接返回 right - left.
滑动窗口,极简代码,新增图解

// 1
class Solution {public int longestOnes(int[] A, int K) {int left=0 ,right=0;while (right<A.length){if(A[right++]==0) K--;if(K < 0) {if(A[left++]==0) K++;}}return right-left;}
}// 2
class Solution {public int longestOnes(int[] A, int K) {int left=0 ,right=0;while (right<A.length){K -= A[right++]^1;if(K < 0) K += A[left++]^1;}return right-left;}
}作者:怕冷的三十三
链接:https://leetcode.cn/problems/max-consecutive-ones-iii/solutions/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

将x减到0的最小操作数

在这里插入图片描述

刚开始看到题目确实感觉难以下手,"移除数组 nums 最左边或最右边的元素"这是什么鬼???

后来想了想,我们只需要让 数组中剩下的元素 = 原始数组中全部元素的和 - x . 就行了.
这道题目也就变成了寻找能满足上面的条件时,数组的最大值.
找到这个最大值然后让 数组的原始长度 - 最大值,就可以得到最小操作数啦~

但是有个坑(踩了两次qwq)

  • 当 原始数组中全部元素的和 - x == 0 时,说明此时不需要进行任何操作(因为元素都是正数),直接返回数组长度就OK
  • 当 原始数组中全部元素的和 - x < 0 时,说明把数组中的所有元素凑起来也凑不出x.此时直接返回-1.

错了好几次,通过不断地画图,分析,总算是做出来了~
代码:

class Solution {public int minOperations(int[] nums, int x) {int max = 0;int left = 0;int right = 0;int sum = 0;int sum2 = 0;for (int i = 0; i < nums.length; i++) sum2 += nums[i];sum2 -= x;if (sum2 < 0) return -1;if (sum2 == 0) return nums.length;while (right < nums.length) {if (sum < sum2) {sum += nums[right++];}while (sum > sum2) {sum -= nums[left++];}if (sum == sum2) {max = Math.max(max, right - left);sum -= nums[left++];}}return max == 0 ? -1 : nums.length - max;}
}

在这里插入图片描述

看了题解,跟我写的差不多,但是我写的还有可以优化的地方.

优化后:

class Solution {public int minOperations(int[] nums, int x) {int max = 0;int left = 0;int right = 0;int sum = 0;int sum2 = 0;for (int i = 0; i < nums.length; i++) sum2 += nums[i];sum2 -= x;if (sum2 < 0) return -1;if (sum2 == 0) return nums.length;while (right < nums.length) {sum += nums[right++];while (sum > sum2)sum -= nums[left++];if (sum == sum2)max = Math.max(max, right - left);}return max == 0 ? -1 : nums.length - max;}
}

水果成篮

在这里插入图片描述
emmm,太久没用HashMap了,都快不会用了.

class Solution {public int totalFruit(int[] fruits) {int max = 0;HashMap<Integer,Integer> hashMap = new HashMap<>();for(int left=0,right=0; right < fruits.length;right++) {hashMap.put(fruits[right],hashMap.getOrDefault(fruits[right],0)+1);while(hashMap.size() > 2) {hashMap.put(fruits[left],hashMap.get(fruits[left])-1);if(hashMap.get(fruits[left]) == 0)hashMap.remove(fruits[left]);left++;}max = Math.max(max,right-left+1);}return max;   }
}

还可以不使用HashMap,因为它给出了
0 <= fruits[i] < fruits.length
可以使用数组来模拟.
多定义了一个 kinds 变量,用来统计水果的种类.

	public int totalFruit2(int[] fruits) {int max = 0;int n = fruits.length;int[] hashMap = new int[n + 1];for (int left = 0, right = 0, kinds = 0; right < fruits.length; right++) {int in = fruits[right];if (hashMap[in] == 0) kinds++;hashMap[in]++;while (kinds > 2) {int out = fruits[left];hashMap[out]--;if (hashMap[out] == 0)kinds--;left++;}max = Math.max(max, right - left + 1);}return max;}

找到字符串中所有字母异位词

在这里插入图片描述
没写出来,最开始是想用两个hashMap,后来写着写着,又改成使用一个hashMap一个数组模拟.再然后又改成一个数组模拟,emmm改来改去,把自己绕晕了~

看了看题解,发现没有我想的那么复杂.
最开始想的是从窗口里一个一个对比P中出现的字符.搞了半天,没写出来.

其实只需要将窗口的长度固定下来就OK.

  1. 入窗口,hash[in]++.
  2. 判断一下right-left+1 是否大于 p字符串的长度.
    • 大于,出窗口
  3. 判断是否要更新结果(right - left + 1 == p字符串的长度)
    • 相等,比较两个hash表中的字符出现次数.如果完全一致,那就更新结果.

也有一些小坑:

  • 字符串s的长度必须要大于字符串p的长度,不然不可能有结果.
  • 如果使用数组模拟hash表,并且设置数组大小为26.那么别忘了要 -'a'.
class Solution {public List<Integer> findAnagrams(String s, String p) {List<Integer> list = new ArrayList<>();int n1 = s.length(), n2 = p.length();if (n1 < n2)return list;char[] ss = s.toCharArray();int[] hash = new int[26];int[] hashP = new int[26];for (int i = 0; i < n2; i++) {hashP[p.charAt(i) - 'a']++;}for (int left = 0, right = 0; right < n1; right++) {char in = ss[right];hash[in - 'a']++;if (right - left + 1 > n2) {char out = ss[left++];hash[out - 'a']--;}if (right - left + 1 == n2) {int i = 0;for (; i < 26; i++) {if (hash[i] != hashP[i]) {break;}}if (i >= 26) {list.add(left);}}}return list;}
}

在以上代码的基础上做一下优化~

上述代码中,在检查两个hash表中的内容是否相等时,用的方法不是很好.
这道题给出了s串和p串中只有小写字母.由于小写字母只有26个,所以检查起来很快.
但是接下来还有一道题目,让你判断两个字符串,如果还是用上面的方法,那就会超时~

具体的优化思路:

维护一个count,count用来记录"有效字符个数".

具体一点:

  1. 进窗口: 如果hash[in] <= hashP[in],那么count++.
  2. 出窗口: 如果hash[out] <= hashP[out],那么count–;
  3. 更新结果: 如果count == p串长度,更新结果.

坑:

  • 注意count维护的时机.

优化后:

class Solution {public List<Integer> findAnagrams2(String s, String p) {List<Integer> list = new ArrayList<>();int n1 = s.length(), n2 = p.length();if (n1 < n2)return list;char[] ss = s.toCharArray();int[] hash = new int[26];int[] hashP = new int[26];for (int i = 0; i < n2; i++) {hashP[p.charAt(i) - 'a']++;}int count = 0;for (int left = 0, right = 0; right < n1; right++) {int in = ss[right] - 'a';hash[in]++;if (hash[in] <= hashP[in]) count++;if (right - left + 1 > n2) {int out = ss[left++] - 'a';if (hash[out] <= hashP[out]) count--;hash[out]--;}if (count == n2) {list.add(left);}}return list;}
}

串联所有单词的子串

在这里插入图片描述
尝试了两次,没写出来.

  • 想不到,可以这样写.
  • String/StringBuilder 中有的方法不知道,而且用的不熟练.比如说substring.
  • 在出窗口这里卡了一下.

看完题解后,自己写出来的代码:
count 的位置和加减容易写错.

public List<Integer> findSubstring(String s, String[] words) {List<Integer> list = new ArrayList<>();int lenS = s.length();int lenWords = words.length;int lenWord = words[0].length();HashMap<String, Integer> hashWords = new HashMap<>();for (String str : words)hashWords.put(str, hashWords.getOrDefault(str, 0) + 1);for (int i = 0; i < lenWord; i++) {HashMap<String, Integer> hashS = new HashMap<>();int count = 0;for (int left = i, right = i + lenWord; right <= lenS; right += lenWord) {String in = s.substring(right - lenWord, right);hashS.put(in, hashS.getOrDefault(in, 0) + 1);if (hashS.get(in) <= hashWords.getOrDefault(in, 0))count++;if (right - left > lenWord * lenWords) {String out = s.substring(left, left + lenWord);if (hashS.get(out) <= hashWords.getOrDefault(out, 0))count--;hashS.put(out, hashS.get(out) - 1);left += lenWord;}if (count == lenWords)list.add(left);}}return list;}

题解代码:

class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> ret = new ArrayList<>();//返回答案HashMap<String, Integer> hash1 = new HashMap<>();//hash1用来记录words中出现过的单词以及对应次数for (String str : words) {hash1.put(str, hash1.getOrDefault(str, 0) + 1);}int len = s.length();int wordLength = words[0].length();int wordsLength = words.length;for (int i = 0; i < wordLength; i++) {HashMap<String, Integer> hash2 = new HashMap<>();for (int right = i, left = i, count = 0; right + wordLength <= len; right += wordLength) {String str = s.substring(right, right + wordLength);hash2.put(str, hash2.getOrDefault(str, 0) + 1);if (hash2.get(str) <= hash1.getOrDefault(str, 0)) {count++;}if (right - left + 1 > wordLength * wordsLength) {String str2 = s.substring(left, left + wordLength);if (hash2.get(str2) <= hash1.getOrDefault(str2, 0)) {count--;}hash2.put(str2,hash2.get(str2)-1);left += wordLength;}if(count == wordsLength) {ret.add(left);}}}return ret;}
}

最小覆盖子串

在这里插入图片描述
emmm,怎么说呢,没写出来,但是看完题解,发现我的代码只需要把一个if改成while就能过了,而且速度很快…

	class Solution {public String minWindow(String ss, String tt) {int min = Integer.MAX_VALUE;char[] s = ss.toCharArray();char[] t = tt.toCharArray();int len = tt.length();StringBuilder ret = new StringBuilder();int count = 0, left1 = 0, right1 = 0;int[] hashS = new int[58];int[] hashT = new int[58];for (char ch : t) hashT[ch - 'A']++;for (int right = 0, left = 0; right < s.length; right++) {int in = s[right] - 'A';hashS[in]++;if (hashS[in] <= hashT[in]) {count++;}while (count == len) {if (min > right - left + 1) {right1 = right;left1 = left;min = right - left + 1;}int out = s[left++] - 'A';if (hashS[out] <= hashT[out])count--;hashS[out]--;}}while (left1 <= right1) {ret.append(s[left1++]);}return min == Integer.MAX_VALUE ? "" : ret.toString();}}

总结

  1. 感觉滑动窗口本质上还是双指针,只不过是同向双指针.
  2. 使用滑动窗口时要用到单调性.
  3. 使用滑动窗口的套路就是:进窗口,出窗口,根据题意找个地方更新结果.
  4. 对于一些需要记录 单词出现次数/种类 的题目,可以定义一个count来优化代码.

本文到这里就结束啦~

在这里插入图片描述

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

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

相关文章

2016年国赛高教杯数学建模D题风电场运行状况分析及优化解题全过程文档及程序

2016年国赛高教杯数学建模 D题风电场运行状况分析及优化 风能是一种最具活力的可再生能源&#xff0c;风力发电是风能最主要的应用形式。我国某风电场已先后进行了一、二期建设&#xff0c;现有风机124台&#xff0c;总装机容量约20万千瓦。请建立数学模型&#xff0c;解决以下…

探索私有化聊天软件:即时通讯与音视频技术的结合

在数字化转型的浪潮中&#xff0c;企业对于高效、安全、定制化的通讯解决方案的需求日益迫切。鲸信&#xff0c;作为音视频通信技术的佼佼者&#xff0c;凭借其强大的即时通讯与音视频SDK&#xff08;软件开发工具包&#xff09;结合能力&#xff0c;为企业量身打造了私有化聊天…

MySQL Mail服务器集成:如何配置发送邮件?

MySQL Mail插件使用指南&#xff1f;怎么优化 MySQL发邮件性能&#xff1f; MySQL Mail服务器的集成&#xff0c;使得数据库可以直接触发邮件发送&#xff0c;极大地简化了应用架构。AokSend将详细介绍如何配置MySQL Mail服务器&#xff0c;以实现邮件发送功能。 MySQL Mail&…

【YashanDB知识库】如何配置jdbc驱动使getDatabaseProductName()返回Oracle

本文转自YashanDB官网&#xff0c;具体内容请见https://www.yashandb.com/newsinfo/7352676.html?templateId1718516 问题现象 某些三方件&#xff0c;例如 工作流引擎activiti&#xff0c;暂未适配yashandb&#xff0c;使用中会出现如下异常&#xff1a; 问题的风险及影响 …

【STM32】江科大STM32笔记汇总(已完结)

STM32江科大笔记汇总 STM32学习笔记课程简介(01)STM32简介(02)软件安装(03)新建工程(04)GPIO输出(05)LED闪烁& LED流水灯& 蜂鸣器(06)GPIO输入(07)按键控制LED 光敏传感器控制蜂鸣器(08)OLED调试工具(09)OLED显示屏(10)EXTI外部中断(11)对射式红外传感器计次 旋转编码器…

K8S服务发布

一 、服务发布方式对比 二者主要区别在于&#xff1a; 1、部署复杂性&#xff1a;传统的服务发布方式通常涉及手动配置 和管理服务器、网络设置、负载均衡等&#xff0c;过程相对复 杂且容易出错。相比之下&#xff0c;Kubernetes服务发布方式 通过使用容器编排和自动化部署工…

QT----Creater14.0,qt5.15无法启动调试,Launching GDB Debugger报红

问题描述 使用QT Creater 14.0 和qt5.15,无法启动调试也没有报错,加载debugger报红 相关文件都有 解决方案 尝试重装QT,更换版本5.15.2,下载到文件夹,shift鼠标右键打开powershell输入 .\qt-online-installer-windows-x64-4.8.0.exe --mirror http://mirrors.ustc.edu.cn…

解决fatal: unable to access ‘https://........git/‘: Recv failure: Operation time

目录 前言 解决方法一 解决方法二 解决方法三 解决方法四 总结 前言 在使用 Git 进行代码拉取时&#xff0c;可能会遇到连接超时的问题&#xff0c;特别是在某些网络环境下&#xff0c;例如公司网络或防火墙严格的环境中。这种情况下&#xff0c;Git 无法访问远程仓…

OpenHarmony(鸿蒙南向)——平台驱动指南【DAC】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 概述 功能简介 DAC&#xff08;Digital to Analog Converter&…

LLM - 使用 RAG (检索增强生成) 多路召回 实现 精准知识问答 教程

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/142629289 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 RAG (R…

windows下 Winobj.exe工具使用说明c++

1、winobj.exe工具下载地址 WinObj - Sysinternals | Microsoft Learn 2、接下来用winobj.exe查看全局互斥&#xff0c;先写一个小例子 #include <iostream> #include <stdlib.h> #include <tchar.h> #include <string> #include <windows.h>…

VS2017安装Installer Projects制作Setup包

下载安装扩展包 VS2017默认未安装Installer Projects Package&#xff0c;需要联机下载&#xff1a; 也可网页上下载离线InstallerProjects.vsix文件&#xff1a; https://visualstudioclient.gallerycdn.vsassets.io/extensions/visualstudioclient/microsoftvisualstudio20…

FPGA IP 和 开源 HDL 一般去哪找?

在FPGA开发的世界中&#xff0c;IP核和HDL模块是构建复杂数字系统的基石。它们如同乐高积木&#xff0c;让开发者能够快速搭建和重用经过验证的电路功能。但你是否曾感到迷茫&#xff0c;不知道从哪里寻找这些宝贵的资源&#xff1f;本文将为你揭开寻找FPGA IP核和HDL模块资源的…

Tesla T4 P2P测试

Tesla T4 P2P测试 一.测试环境二.测试步骤1.获取设备信息2.查看PCIE拓扑结构3.选择9B、9E这二张4.查看逻辑设备ID5.设置环境变量(需要用逻辑设备ID,通过UUID跟smi看到的物理ID关联)6.不同地址的原子操作2.P2P与非P2P的性能差异3.GPU带宽测试 Tesla T4 P2P测试 通过物理ID找到逻…

2024PT展,现场精华

9月25-27日&#xff0c;2024年国际信息通信展&#xff08;简称PT展&#xff09;在北京国家会议中心召开。 小枣君去了现场&#xff0c;也拍了一些照片&#xff0c;特此分享给大家。 会场离“奥林匹克公园”地铁站很近&#xff1a; Logo设计得还是挺好看的&#xff1a; 熟悉的场…

一区黏菌算法+双向深度学习+注意力机制!SMA-BiTCN-BiGRU-Attention黏菌算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测

一区黏菌算法双向深度学习注意力机制&#xff01;SMA-BiTCN-BiGRU-Attention黏菌算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测 目录 一区黏菌算法双向深度学习注意力机制&#xff01;SMA-BiTCN-BiGRU-Attention黏菌算法优化双向时间卷积双向门控循环单元…

探索机器人快换盘技术的未来之路:智能化与协作的革新

在当今快速发展的科技时代&#xff0c;机器人已成为众多领域不可或缺的得力助手。其中&#xff0c;机器人快换盘技术作为提升机器人灵活性和应用广度的重要技术&#xff0c;正经历着前所未有的变革与创新。下面请随我们一起深入探讨这一技术的未来发展趋势。 一、人工智能&…

<<迷雾>> 第 4 章 电子计算机发明的前夜 示例电路

莫尔斯电报示意图 info::操作说明 鼠标单击开关切换开合状态 通电后, 线圈产生磁力从而将铁片开关(衔铁臂)吸引下来 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/cyjsjdmw-examples/assets/circuit/cyjsjdmw-ch04-01-morse-te…

Shopline对接需要注意的问题

Shopline对接是一项复杂而细致的工作&#xff0c;为了确保对接的顺利进行&#xff0c;并保证系统的稳定性和可靠性&#xff0c;需要注意以下几个方面。 1.API文档的详细阅读 功能理解&#xff1a; 仔细阅读Shopline提供的API文档&#xff0c;全面了解每个接口的功能、参数、返…

初始docker以及docker的基本使用!!!

文章目录 虚拟化技术Docker/podman 命令通用命令查看docker 当前版本管理docker运行 镜像操作[image]列出本地所有镜像拉取镜像删除镜像把docker中的镜像打包成文件把镜像文件加载到docker中上传镜像 容器操作[container]创建容器docker run的参数选项列出所有容器启动容器停止…