滑动窗口题解2

目录

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

分析:

代码展示:

代码展示:

2 串联所有单词的子串

分析:

代码展示:

3 串联所有单词的子串

分析:

代码展示:

4 水果成篮

分析:

代码展示:


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

分析:

这道题我们首先想到的暴力解法就是枚举出所有的可能字串然后进行判断就行。而最大的难点在于判断是否相同。

我们先来讲该暴力解法的优解,滑动窗口。经过前几题的练习应该很容易想到这种字串问题用滑动窗口。滑动窗口就不多赘述,我们来介绍这道题的细节和难点;

1  遍历详细过程:我们首先要定义两个Map<Character,Interger>,分表存储p和遍历过的s。定义两个指针left 和 right。right向右遍历,当遇到一个字符就存入map。假设p的字符数为3,直到right和left之间存入三个字符时,进行判断,成立的话则存入list,然后left++,right++。直到right遍历到s最后一个字符。

2  判断相同的两种方式

1 创建两个map,一个存储字符串p,另一个存储遍历过s的,并且用一个for遍历字符串p,如果两个map.getOrDefault(key,0)返回的值均相同那么就符合要求;

2 创建两个map,mapS和mapP。我们创建一个变量count。来记录right遍历的时候存入的有效字符。什么是有效字符,比如p的字符个数为2,那么我们用滑动窗口遍历字符串s的时候,如果这个字符在mapP中,并且mapS的该字符个数小于等于mapP时我们就count++,如果遇到的字符不在mapP中count就不++。最后判断count是否等于p.length()即可。

后面会多次用到整个方法,请理解记住。

代码展示:
class Solution {public  List<Integer> findAnagrams(String s, String p) {int left = 0;int right = 0;Map<Character,Integer> mapS = new HashMap<>();Map<Character,Integer> mapP = new HashMap<>();int count = 0;List<Integer> list = new ArrayList<>();for (int i = 0; i < p.length(); i++) {int total = mapP.getOrDefault(p.charAt(i) , 0) + 1;mapP.put(p.charAt(i) , total);}while( right < s.length()) {int total = mapS.getOrDefault(s.charAt(right) , 0) + 1;mapS.put(s.charAt(right) , total);if(mapS.getOrDefault(s.charAt(right) , 0) <= mapP.getOrDefault(s.charAt(right),0) ) {count++;}right++;if(count == p.length()) {list.add(left);}if(right - left  >= p.length()) {if(mapS.getOrDefault(s.charAt(left) , 0) <= mapP.getOrDefault(s.charAt(left),0) ) {count--;}int out = mapS.getOrDefault(s.charAt(left) , 0) - 1;mapS.put(s.charAt(left) , out);left++;}}return list;}
}

这个运行结果时间不是最优的,是因为hashMap,我们将map换成计数数组即可。即创建int[] c = new int[26],字符a的存储下标:'a' - 'a' 。不过map的通用性较强。

代码展示:
class Solution {public  List<Integer> findAnagrams(String s, String p) {int left = 0;int right = 0;int[] mapS = new int[26];int[] mapP = new int[26];int count = 0;List<Integer> list = new ArrayList<>();for (int i = 0; i < p.length(); i++) {mapP[p.charAt(i) - 'a']++;}while( right < s.length()) {if(++mapS[s.charAt(right) - 'a'] <= mapP[s.charAt(right) - 'a']) {count++;}if(count == p.length()) {list.add(left);}if(++right - left  >= p.length()) {if(mapS[s.charAt(left) - 'a']-- <= mapP[s.charAt(left) - 'a']) {count--;}left++;}}return list;}
}

我们看出这个代码简化了很多。

2 串联所有单词的子串
分析:

这道题和上一题如出一辙,只是上一题是字符,这道题是字符串,核心解法是不变的。假设word每个元素长度是3 ,我们遍历s的时候每次以3为一组进行遍历即可。

这道题有两个难点:

demo: s = "cabcd"  words = ["ab",'cd'].;  len = words[0].length();

1 示例中未给出所有可能情况;

这个示例的返回结果应该是[1];但是当我们以0开始遍历的时候,每次遍历程度为2,此时是无法得出结果的。因此,我们要让left和right从0开始完整遍历一次,从1开始完整遍历。当我们再2开始遍历的时候可以发现和从0开始遍历是相同的,因此到2的时候就无需再遍历一次了。这时候得到的才是完整答案;

2 条件。

当我们从0开始遍历的时候,如果整个遍历的循环条件是:right < s.length()。那么由于right每次遍历两个元素,就会越界,因此我们的条件应该是:right + len <= s.length();

代码展示:
class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> list = new ArrayList<>();int len = words[0].length();int totalL = len * words.length;int sum = 0;while(sum  < len) {int left = sum;int right = sum;Map<String, Integer> map1 = new HashMap<>();Map<String, Integer> map2 = new HashMap<>();int count = 0;for (int i = 0; i < words.length; i++) {int tmp = map2.getOrDefault(words[i], 0) + 1;map2.put(words[i], tmp);}while (right + len <= s.length()) {
//                int k = right;
//                char[] c = new char[len];
//                while (k < s.length() && k < len + right) {
//                    c[k - right] = s.charAt(k);
//                    k++;
//                }
//                String s1 = new String(c);String s1 = s.substring(right,right + len);int tmp = map1.getOrDefault(s1, 0) + 1;map1.put(s1, tmp);right = right + len;if (map1.getOrDefault(s1, 0) <= map2.getOrDefault(s1, 0)) {count++;}if (right - left >= totalL) {if (count == words.length) {list.add(left);}//int index = left;
//                    char[] c2 = new char[len];
//                    while (index < s.length() && index < len + left) {
//                        c2[index - left] = s.charAt(index);
//                        index++;
//                    }s1 = s.substring(left,left + len);if (map1.getOrDefault(s1, 0) <= map2.getOrDefault(s1, 0)) {count--;}tmp = map1.get(s1) - 1;map1.put(s1, tmp);left = left + len;}}sum++;}return list;}
}
3 串联所有单词的子串

分析:

这道题仍然是不管先后顺序,只要包含t中的字串就行。因此我们判断字串是否包含t的全部元素并相同的时候我们仍然可以使用count去标记。

首先看到这样的题目描述以及求字串那么我们想到的解法一定是滑动窗口;那么我们就要想一下进窗口,出窗口,和更新结果的时机以及条件。

我们先是定义两个指针,left和right。right向后依次遍历。每次遍历过的字符都放入集合里。并且判段该元素是否在t中存在,并且数量小于t中对应字符的数量,如果是那么count++; 接下来我们需要判断,当前的right和left之间的字符串是否满足条件,即count是否等于t.length。相等话如果长度小于之前满足要求的字符串则更新结果。之后再对left进行++。

以上就是大体思路

优化点:

我们可以将map或作数组,方法和题一一样,将string转为字符,然后-'a'存入数组。这样时间可以减短很多

代码展示:

    public static String minWindow(String s, String t) {Map<String ,Integer> map1 = new HashMap<>();Map<String ,Integer> map2 = new HashMap<>();String result = "";for (int i = 0; i < t.length(); i++) {map2.put(t.substring(i,i+1),map2.getOrDefault(t.substring(i,i+1),0) + 1);}int right = 0;int left = 0;int count = 0;int min = s.length();while(right < s.length()) {String tmp = s.substring(right,right + 1);map1.put(tmp,map1.getOrDefault(tmp,0) + 1);if(map1.get(tmp) <= map2.getOrDefault(tmp , 0)) {count++;}right++;if(map1.containsKey(tmp)) {while(count == t.length()) {if(min >= (right - left)) {min = right - left;result = s.substring(left , right);}tmp = s.substring(left,left + 1);if(map1.get(tmp) <= map2.getOrDefault(tmp , 0)) {count--;}map1.put(tmp,map1.getOrDefault(tmp,0) - 1);left++;}}}return result;}
4 水果成篮

分析:

遇到这种连续数组求字串或者长度之类的用滑动窗口。这道题的思考点在于如何直到是否有两种以上的不同数字,我们可以用map,如果map.size()没有超过2,那么继续往里面加,如果超过2那么就左移left。然后每次移动的时候更新最大值即可。

代码展示:
class Solution {public int totalFruit(int[] fruits) {Map<Integer , Integer> map = new HashMap<>();int right = 0;int left = 0;int max = 0;while(right < fruits.length) {int tmp = map.getOrDefault(fruits[right] , 0) + 1;map.put(fruits[right] , tmp);right++;while (map.size() > 2) {tmp = map.getOrDefault(fruits[left] , 0) - 1;map.put(fruits[left] , tmp);if (map.get(fruits[left]) == 0) {map.remove(fruits[left]);}left++;}if(right - left> max) {max = right - left ;}}return max;}
}

下一章节我们开始讲二分法。

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

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

相关文章

障碍物识别技术赋能盲人独立出行:一场静默的科技革新

作为一名资深记者&#xff0c;我始终关注并报道那些科技如何助力特殊群体克服生活挑战的动人故事。近期&#xff0c;一款叫做蝙蝠避障的应用进入了我的视线&#xff0c;它搭载先进障碍物识别技术以其独特的优势&#xff0c;悄然为视障人士的独立出行带来了显著变革。 “障碍物识…

一.shell基本知识

目录 1.1为什么学习和使用Shell编程 1.2什么是Shell 1.2.1 shell的起源 1.2.2shell的功能 1.3shell的分类 1.4作为程序设计的语言一—shell 1.5如何学好shell 1.6shell脚本的基本元素 1.7 shell脚本编写规范 1.8 shell脚本的执行方式 1.9 执行脚本的方法 1.10 shel…

ChatGML-6B大模型Windows部署(可CPU运行 保姆级教程)

&#x1f680; 写在最前&#xff1a;这篇文章将学习如何运行ChatGML-6B大模型。 &#x1f680;&#xff1a;点个关注吧&#x1f600;&#xff0c;让我们一起探索计算机的奥秘&#xff01; 一、ChatGML-6B大模型介绍 ChatGML-6B 是一个大型语言模型,被训练来预测人类语言。它是…

人工智能基础部分26-基于知识推理引擎KIE算法的原理介绍与实际应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能基础部分26-基于知识推理引擎KIE算法的原理介绍与实际应用。知识推理引擎(Knowledge Inference Engine, KIE)是一种人工智能技术&#xff0c;其核心原理是基于规则和逻辑的方法来处理复杂的问题。它构建在业…

华为欧拉系统(openEuler-22.03)安装深信服EasyConnect软件(图文详解)

欧拉镜像下载安装 iso镜像官网下载地址 选择最小化安装&#xff0c;标准模式 换华为镜像源 更换华为镜像站&#xff0c;加速下载&#xff1a; sed -i "s#http://repo.openeuler.org#https://mirrors.huaweicloud.com/openeuler#g" /etc/yum.repos.d/openEuler.r…

MongoDB 初识

1.介绍 什么是Mong MongoDB是一种开源的文档型数据库管理系统&#xff0c;它使用类似于JSON的BSON格式&#xff08;Binary JSON&#xff09;来存储数据。与传统关系型数据库不同&#xff0c;MongoDB不使用表和行的结构&#xff0c;而是采用集合&#xff08;Collection&#x…

Leetcode刷题之删除链表中等于给定值 val 的所有结点

Leetcode刷题之删除链表中等于给定值 val 的所有结点 一、题目描述二、题目解析 一、题目描述 Leetcode刷题之删除链表中等于给定值 val 的所有结点 二、题目解析 本题中我们需要将链表中等于val的值的节点删除&#xff0c;首先我想到的方法是通过暴力求解解决&#xff0c;…

递归、搜索与回溯算法:⼆叉树中的深搜

⼆叉树中的深搜 深度优先遍历&#xff08;DFS&#xff0c;全称为 Depth First Traversal&#xff09;&#xff0c;是我们树或者图这样的数据结构中常⽤的 ⼀种遍历算法。这个算法会尽可能深的搜索树或者图的分⽀&#xff0c;直到⼀条路径上的所有节点都被遍历 完毕&#xff…

【Java】maven的生命周期和概念图

maven的生命周期&#xff1a; 在maven中存在三套"生命周期"&#xff0c;每一套生命周期,相互独立,互不影响的,但是中同一套生命周期里,执行后面的命令会自动先执行前面的命令 CleanLifeCycle&#xff1a;清理的生命周期 clean defaultLifeCycle&#xff1a;默认的…

docker-compose yaml指定具体容器网桥ip网段subnet;docker创建即指定subnet;docker取消自启动

1、docker-compose yaml指定具体容器网桥ip网段subnet docker-compose 启动yaml有时可能的容器网段与宿主机的ip冲突导致宿主机上不了网&#xff0c;这时候可以更改yaml指定subnet 宿主机内网一般是192**&#xff0c;这时候容器可以指定172* version: 3.9 services:coredns:…

解锁生成式 AI 的力量:a16z 提供的 16 个企业指南

企业构建和采购生成式AI方面的16项改变 生成式 AI 领域趋势洞察&#xff1a;企业构建和采购生成式 AI 的方式正在发生重大转变&#xff0c;具体表现在&#xff1a;* 专注于可信度和安全性&#xff1a;75% 的企业将信任和安全性视为关键因素。* 优先考虑可扩展性和灵活性&#x…

go语言并发实战——日志收集系统(一) 项目前言

-goroutine- 简介 go并发编程的练手项目 项目背景 一般来说业务系统都有自己的日志,当系统出现问题时,我们一般需要通过日志信息来定位与解决问题&#xff0c;当系统机器较少时我们可以登录服务器来查看,但是当系统机器较多时,我们通过服务器来查看日志的成本就会变得很大,…

状态模式【行为模式C++】

1.概述 状态模式是一种行为设计模式&#xff0c; 让你能在一个对象的内部状态变化时改变其行为&#xff0c; 使其看上去就像改变了自身所属的类一样。 2.结构 State(抽象状态类)&#xff1a;定义一个接口用来封装与上下文类的一个特定状态相关的行为&#xff0c;可以有一个或多…

element问题总结之el-table使用fixed固定列后滚动条滑动到底部或者最右侧的时候错位问题

el-table使用fixed固定列后滚动条滑动到底部或者最右侧的时候错位 效果图前言解决方案纵向滑动滚动条滑动到底部的错位解决横向滚动条滑动到最右侧的错位解决 效果图 前言 在使用el-table固定行的时候移动滚动条会发现移动到底部或者移动到最右侧的时候会出现表头和内容错位或…

Mac电脑安装蚁剑

1&#xff1a; github 下载源码和加载器&#xff1a;https://github.com/AntSwordProjectAntSwordProject GitHubAntSwordProject has 12 repositories available. Follow their code on GitHub.https://github.com/AntSwordProject 以该图为主页面&#xff1a;antSword为源码…

PHPStudy(小皮)切换PHP版本PDO拓展失效的问题

因为要看一个老项目&#xff0c;PHP版本在8.0以上会报错&#xff0c;只能切换到7.2&#xff0c;但又遇到了PDO没开启的问题。 PHPStudy上安装的PHP7.2是需要自己配置一下的&#xff0c;里面php.ini文件是空的&#xff0c;需要将php.ini-development改成php.ini&#xff0c;对于…

【每日刷题】Day15

【每日刷题】Day15 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; 目录 1. 141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 2. 142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09; 3. 143. 重…

ROS 2边学边练(25)-- 将多个节点组合到一个进程

前言 在ROS 2中&#xff0c;将多个节点&#xff08;Nodes&#xff09;组合到一个单独的进程&#xff08;Process&#xff09;中通常指的是使用“Composable Nodes”的特性。这个特性允许你定义可复用的组件&#xff08;Components&#xff09;&#xff0c;然后将这些组件加…

WPF-基础及进阶扩展合集(持续更新)

目录 一、基础 1、GridSplitter分割线 2、x:static访问资源文件 3、wpf触发器 4、添加xaml资源文件 5、Convert转换器 6、多路绑定与多路转换器 二、进阶扩展 1、HierarchicalDataTemplate 2、XmlDataProvider从外部文件获取源 3、TextBox在CellTemplate中的焦点问题…