[Java][算法 滑动窗口]Day 03---LeetCode 热题 100---08~09

第一题  无重复字符串的最长子串

思路

其实就是在字符串S中 找到没有重复的最长子串的长度  这道题的难点就是在于如何判断最长并且无重复

首先 最长长度  可以使用变量max记录保存   

再者 判断有无重复  最简单的方法就是  暴力遍历法  即对于每次找的子串都再次寻找遍历一次  判断是否已有字符  自然  这种方法判断的话 时间复杂度会不是一般的高

当然 算法优化我们慢慢再讨论  最直接的思路就是如此

解法一:暴力法

我们的暴力当然和上述思路不太一样  我们对于是否重复  可以直接利用Map集合key不能重复的特点  然后使用containKey()方法直接进行判断

class Solution {
   public static int lengthOfLongestSubstring(String s) {
// 对于S的特殊情况直接返回0
        if(s==null || s.length()==0) return 0;
//将S转化为char数组[]  遍历该数组 然后进行判断
        char[] charArray = s.toCharArray();int max=1;
        Map<Character,Integer> map=new HashMap<>();
//遍历  每次遍历开始就是认定为子串的起始字符
        for(int i=0;i< charArray.length;i++){
//每次记录完一次后 需要把map清空
            map.clear();
            map.put(charArray[i],i); //将第一个字符放入
            for(int j=i+1;j< charArray.length;j++){
                if(map.containsKey(charArray[j])){ // 利用containKey方法直接判断
                    if(map.size()>max) max=map.size(); // 判断当前map长度和max进行比较
                    break;
                }else{
                    map.put(charArray[j],j);
                }
            }
            if(map.size()>max) max=map.size();
        }
        return max;
    }
}

解法二:滑动窗口法

所谓滑动窗口,其实就是在字符串中先选定一段,把这段作为一个可以滑动的窗口,这个窗口类似于队列,每次判断队列中字符是否满足题目条件,不满足即向左滑动(这是整体情况下 一般是向左  自然 也可以只会滑动右边界),滑动窗口的时候,自然左边会少一位,右边会多一位。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s.length()==0) return 0;
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        int max = 0;
        int left = 0;
        for(int i = 0; i < s.length(); i ++){
            if(map.containsKey(s.charAt(i))){ //判断是否存在已有队列中
//有的话 找到map中该重复的元素的索引位置 判断两者索引大小 通过对索引的判断 不断向右滑动变化起点
                left = Math.max(left,map.get(s.charAt(i)) + 1);  
            }
            map.put(s.charAt(i),i);//不存在则添加到map中
            max = Math.max(max,i-left+1); // 更新最大长度
        }
        return max;
        
    }
}

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

思路

和第一题类似 也是遍历找子串  只是这个题目判断依据  不是重复 而是找异位词  异位词的定义我们之前也遇到过 简单来说 就是字母组成一样   如果是异位词 那么排序后的字符串两者一定是一样的  所以我们对其的判断方式就是排序后是否一样  那么这道题的解题思路就很明确

需要注意字符串长度  判null等特殊情况

解法一:暴力法

同样的 直接暴力遍历  然后判断是否为异位词就行即可

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        if(s==null||p.length()>s.length()) return new ArrayList<>();
        char[] pArray = p.toCharArray();
        Arrays.sort(pArray);
        ArrayList<Integer> list = new ArrayList<>();
        int i=0;int l=p.length();
        //   abvdef   ab
        for(i=0;i<=s.length()-l;i++){
            char[] sArray = s.substring(i, i + l).toCharArray();
            Arrays.sort(sArray);
            if(String.valueOf(pArray).equals(String.valueOf(sArray))){
                list.add(i);
            }
        }
        return list;
    }
}

我们是采用排序的方式进行判断异位词  当然也可以采用哈希表映射 统计字母次数的方式  代码如下

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        int sLen = s.length(), pLen = p.length();

        if (sLen < pLen) {
            return new ArrayList<Integer>();
        }

        List<Integer> ans = new ArrayList<Integer>();
        int[] sCount = new int[26];
        int[] pCount = new int[26];
        for (int i = 0; i < pLen; ++i) {
            ++sCount[s.charAt(i) - 'a'];
            ++pCount[p.charAt(i) - 'a'];
        }

        if (Arrays.equals(sCount, pCount)) {
            ans.add(0);
        }

        for (int i = 0; i < sLen - pLen; ++i) {
            --sCount[s.charAt(i) - 'a'];
            ++sCount[s.charAt(i + pLen) - 'a'];

            if (Arrays.equals(sCount, pCount)) {
                ans.add(i + 1);
            }
        }

        return ans;
    }
}

解法二:滑动窗口法

我们不再分别统计滑动窗口和字符串 p 中每种字母的数量,而是统计滑动窗口和字符串 p 中每种字母数量的差;并引入变量 differ来记录当前窗口与字符串 p 中数量不同的字母的个数,并在滑动窗口的过程中维护它。

在判断滑动窗口中每种字母的数量与字符串 ppp 中每种字母的数量是否相同时,只需要判断 differ是否为零即可

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> res = new ArrayList<Integer>();
        int sLen = s.length();
        int pLen = p.length();

        if(sLen < pLen) {
            return res;
        }
        //表示字母出现次数差距
        //count[x] = 0  表示 s与p中字母x出现次数相同 都出现了n次(n>=0)
        //count[x] = n  表示 在s中字母x出现次数比p多 多出现了n次(n>0)
        //count[x] = -n 表示 在s中字母x出现次数比p少 少出现了n次(n>0)
        int[] count = new int[26];

        for(int i = 0; i < pLen; i++){
            ++count[s.charAt(i)-'a'];
            --count[p.charAt(i)-'a'];
        }
        //表示字母差异个数
        int differ = 0;
        for(int j = 0; j < 26; j++){
            if(count[j]!=0)++differ;
        }

        if(differ==0){
            res.add(0);
        }
        //向右滑动
        for(int i = 0; i < sLen - pLen; i++){
            //缩减时只考虑count[x]==1与count[x]==0的情况
            //因为缩减时字母x减少,count[x]会减去1
            //(1)count[x]==1时(次数差距1次,不相同)  
            //count[x]==0 -> 次数相同 -> 不相同变相同,字母差异个数减少1 -> differ--

            //(2)count[x]==0时(次数相同)  
            //count[x]==-1 -> 次数差距变为1次->相同变不相同 ,字母差异个数增加1 -> differ++

            //(3)count[x]==-1时(次数不相同) -> count[x]==-2 次数还是不相同-> 字母差异数不变

            //(4)count[x]==2时(次数不相同)  -> count[x]==1 次数还是不相同-> 字母差异数不变


            //左缩减一位,i
            if (count[s.charAt(i) - 'a'] == 1) {  
                //窗口中s子串左边减少一个s[i]的数量(把原来多出来的1个s[i]去掉,变得相同)
                //两个字符串字母差距缩小
                --differ;
            } else if (count[s.charAt(i) - 'a'] == 0) {  
                //窗口中s子串左边减少一个s[i]的数量(把原来相同数量的s[i]的减少了1个,数量变得不相同)
                //两个字符串字母差距增大
                ++differ;
            }
            //窗口中s子串左边减少一个字母s[i]
            --count[s.charAt(i) - 'a'];

            //添加时只考虑count[x]==-1与count[x]==0的情况,原因分析与缩减时类似
            //右添加一位,i+pLen
            if (count[s.charAt(i + pLen) - 'a'] == -1) {  
                //窗口中s子串右边增加一个s[i+pLen]的数量(把原来缺少的1个s[i]加上,数量变得相同)
                //两个字符串字母差距缩小
                --differ;
            } else if (count[s.charAt(i + pLen) - 'a'] == 0) {  
                //窗口中s子串右边增加一个s[i+pLen]的数量(把原来相同数量的s[i]多加了1个,变得不相同)
                //两个字符串字母差距增大
                ++differ;
            }
            //窗口中s子串右边增加一个字母s[i+pLen]
            ++count[s.charAt(i + pLen) - 'a'];
            //两个字符串字母差距为0
            if (differ == 0) {
                res.add(i + 1);
            }
        }
        return res;  
    }
}

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

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

相关文章

【十九】【C++】 priority_queue简单使用和仿函数

priority_queue文档介绍翻译 优先队列是一种容器适配器&#xff0c;专门设计成其中的第一个元素始终是根据某种严格的弱排序准则最大的元素。 这种上下文类似于堆&#xff0c;其中元素可以在任何时刻插入&#xff0c;而只能检索最大堆元素&#xff08;在优先队列中顶部的元素&a…

为自监督学习重构去噪扩散模型

在这项研究中&#xff0c;作者检验了最初用于图像生成的去噪扩散模型&#xff08;DDM&#xff09;的表示学习能力。其理念是解构DDM&#xff0c;逐渐将其转化为经典的去噪自动编码器&#xff08;DAE&#xff09;。这一解构过程让大家能够探索现代DDM的各个组成部分如何影响自监…

【Docker】Docker Container操作案例 | 综合实战

文章目录 Docker Container操作案例容器的基本操作容器状态迁移容器批量处理技巧容器交互模式attached模式detached模式interactive模式 容器与宿主机内容复制容器自动删除容器自动重启容器环境变量设置容器详情查看容器执行单行命令容器镜像导入导出容器日志查看容器资源查看 …

C++:多态

C&#xff1a;多态 虚函数虚函数语法虚函数重写协变接口继承 多态构成成员函数状态对比抽象类多态原理多继承与多态虚继承与多态 先看到多态的定义&#xff1a; C的多态是指在面向对象程序设计中&#xff0c;允许使用基类的指针或引用来调用派生类的虚函数的特性。这样的调用将…

数据结构-并查集

并查集原理 在一些应用问题中&#xff0c;需要将n个不同的元素划分成一些不相交的集合。开始时&#xff0c;每个元素自成一个 单元素集合&#xff0c;然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询一 个元素归属于那个集合的运算。适合于描述这类…

阿里云幻兽帕鲁服务器配置4核16G10M带宽够8个人玩吗?玩起来流畅度怎么样?

阿里云幻兽帕鲁服务器配置4核16G10M带宽这个&#xff0c;个人实测下来&#xff0c;五六个人玩是比较流畅的&#xff0c;不过8个人的话&#xff0c;估计会有点卡。如果是8个人的话&#xff0c;我建议选择8核32G那个配置&#xff0c;更加适合一些。 阿里云一键部署幻兽帕鲁详细教…

【lesson57】信号量和生产者消费者模型(环形队列版)

文章目录 信号量概念信号量接口初始化销毁等待发布 基于环形队列的生产者消费者模型编码Common.hLockGuard.hppTask.hppsem.hppRingQueue.hppConProd.cc 信号量概念 POSIX信号量和SystemV信号量作用相同&#xff0c;都是用于同步操作&#xff0c;达到无冲突的访问共享资源目的…

漫漫数学之旅022

文章目录 经典格言数学习题古今评注名人小传- 刘易斯卡罗尔 经典格言 艾丽斯笑着说&#xff1a;“去尝试也毫无用处&#xff0c;一个人无法相信不可能的事情。”——刘易斯卡罗尔&#xff08;Lewis Carroll&#xff09;《艾丽斯梦游仙境&#xff08;Alice in Wonderland&#…

零基础怎么学编程,免费版中文编程工具下载及构件用法教程

零基础怎么学编程&#xff0c;免费版中文编程工具下载及构件用法教程 一、前言 今天给大家分享的中文编程开发语言工具资料如下&#xff1a; 编程入门视频教程链接 http://​ https://edu.csdn.net/course/detail/39036 ​ 编程工具及实例源码文件下载可以点击最下方官网…

基于Python实现Midjourney集成到(个人/公司)平台中

目前Midjourney没有对外开放Api&#xff0c;想体验他们的服务只能在discord中进入他们的频道进行体验或者把他们的机器人拉入自己创建的服务器中&#xff1b;而且现在免费的也用不了了&#xff0c;想使用就得订阅。本教程使用midjourney-api这个开源项目&#xff0c;搭建Midjou…

Linux第55步_根文件系统第2步_测试使用busybox生成的根文件系统

测试使用busybox生成的根文件系统。测试内容较多&#xff0c;很杂。 1、修改“nfs-kernel-server” 1)、打开终端 输入“sudo vi /etc/default/nfs-kernel-server回车”&#xff0c;打开“nfs-kernel-server”文件。 输入密码“123456回车” 见下图&#xff1a; 2)、在最后…

【学网攻】 第(28)节 -- OSPF虚链路

系列文章目录 目录 系列文章目录 文章目录 前言 一、什么是OSPF虚链路&#xff1f; 二、实验 1.引入 实验目标 实验背景 技术原理 实验步骤 实验设备 实验拓扑图 实验配置 扩展 实验拓扑图 实验配置 实验验证 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻…

模型 4S(满意、服务、速度、诚意)理论

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_总纲目录。重在提升认知。以客户为中心。 1 4S(满意、服务、速度、诚意)理论的应用 1.1 4S 理论在制造业中的应用 某汽车制造企业 A 一直致力于提供高品质的汽车产品和优质的服务&#xff0c;以满足客户的需求和期…

2022年12月电子学会青少年软件编程 中小学生Python编程等级考试二级真题解析(选择题)

2022年12月Python编程等级考试二级真题解析 选择题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 1、运行下列程序&#xff0c;最终输出的结果是 info {1:小明,2:小黄,3:小兰} info[4]小红 info[2]小白 print(info) A、{1:小明,2:小白,3:小红,4:小…

高德地图上绘制热力图的方法

百度地图和高德地图的JavaScript API都提供了热力图的绘制方法&#xff0c;都是将热力图作为新的图层&#xff0c;叠加到地图上。但是百度地图的经纬度体系与我们的经纬度存在偏差&#xff0c;高德的与我们相符&#xff0c;应当使用高德地图JavaScript API。 因为是JavaScript…

最长连续手牌 - 华为OD统一考试

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 200分 题解&#xff1a; Java / Python / C 题目描述 有这么一款单人卡牌游戏&#xff0c;牌面由颜色和数字组成&#xff0c;颜色为红、黄、蓝、绿中的一种&#xff0c;数字为 0−9 中的一个。游戏开始时玩家从手牌中…

【题解】差分

差分其实就是前缀和的逆运算。 如果数组 A 是数组 B 的前缀和数组&#xff0c;则称 B 是 A 的差分数组。 思路 由题意得&#xff0c;应该求给定数组的差分数组。 差分加速的原理 对 L 到 R 区间内的数加上 c&#xff0c;时间复杂度是O(c) &#xff0c;即O(n) 。 但是如果…

SORA:OpenAI最新文本驱动视频生成大模型技术报告解读

Video generation models as world simulators&#xff1a;作为世界模拟器的视频生成模型 1、概览2、Turning visual data into patches&#xff1a;将视觉数据转换为补丁3、Video compression network&#xff1a;视频压缩网络4、Spacetime Latent Patches&#xff1a;时空潜在…

NetMizer 日志管理系统 多处前台RCE漏洞复现

0x01 产品简介 NetMizer是提供集成应用交付和应用安全解决方案以实现业务智能网络的优秀全球供应商,为全球企业和运营商提供确保关键业务应用的全面可用性、高性能和完善的安全性的解决方案。 0x02 漏洞概述 NetMizer 日志管理系统position.php、hostdelay.php、等接口处存在…

leetcode刷题--贪心算法

七. 贪心算法 文章目录 七. 贪心算法1. 605 种花问题2. 121 买卖股票的最佳时机3. 561 数组拆分4. 455 分发饼干5. 575 分糖果6. 135 分发糖果7. 409 最长回文串8. 621 任务调度器9. 179 最大数10. 56 合并区间11. 57 插入区间13. 452 用最少数量的箭引爆气球14. 435 无重叠区间…