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

news2024/11/28 0:53:18

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

思路

其实就是在字符串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.coloradmin.cn/o/1448494.html

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

相关文章

【Django】Django内建用户系统

Django内建用户系统 14.1 Django中的用户认证 Django带有一个用户认证系统系统&#xff0c;它处理用户用户账号、组、权限以及基于cookie的用户会话。 用户可以直接使用Django自带的用户表。 官方文档&#xff1a;https://docs.djangoproject.com/zh-hans/2.2/topics/auth/ …

计算机组成原理 2 数据表示

机器数 研究机器内的数据表示&#xff0c;目的在于组织数据&#xff0c;方便计算机硬件直接使用。 需要考虑&#xff1a; 支持的数据类型&#xff1b; 能表示的数据精度&#xff1b; 是否有利于软件的移植 能表示的数据范围&#xff1b; 存储和处理的代价&#xff1b; ... 真值…

ELAdmin 配置定时任务

定义方法 在自己的 Module 中写个要执行的方法。 比如获取微信公众号的 accessToken&#xff0c;每两个小时更新一次。这种的其实使用 Spring 的 Scheduled 更方便些&#xff0c;此处仅为演示。 package me.zhengjie.mp.task;import com.alibaba.fastjson.JSON; import lombo…

基于Linux的nfs、samba网络服务搭建

我学的Ubuntu&#xff0c;以它为例子 一、nfs(linux <---> linux) 1.1.nfs首先搭建服务端&#xff08;对外共享&#xff09; //安装nfs核心服务 sudo apt update sudo apt install nfs-kernel-server //配置nfs文件(指定共享文件) sudo vim /etc/exports //重启nf…

H5 渐变3D旋转个人主页引导页源码

H5 渐变3D旋转个人主页引导页源码 源码介绍&#xff1a;一款渐变3D旋转个人主页引导页源码&#xff0c;可以做个人主页/旗下网站引导 下载地址&#xff1a; https://www.changyouzuhao.cn/10392.html

第三百四十五回

文章目录 1. 概念介绍2. 方法与功能2.1 基本用法2.2 加密算法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"FlutterCacheManager组件"相关的内容&#xff0c;本章回中将介绍一个加密工具包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 加密主要…

【MySQL进阶之路】通过实操理解 explain 执行计划

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

【刷题记录】——2024寒假day9编程题

本系列博客为个人刷题思路分享&#xff0c;有需要借鉴即可。 1.目录大纲&#xff1a; 2.题目链接&#xff1a; T1:LINK T2:LINK 3.详解思路&#xff1a; T1: 思路&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/#include<…

计算机网络——11EMail

EMail 电子邮件&#xff08;EMail&#xff09; 3个主要组成部分 用户代理邮件服务器简单邮件传输协议&#xff1a;SMTP 用户代理 又名“邮件阅读器”撰写、编辑和阅读邮件输入和输出邮件保存在服务器上 邮件服务器 邮箱中管理和维护发送给用户的邮件输出报文队列保持待发…

【成长记录】第一次写博客入csdn榜单了 还是第一.....

庆祝一下第一次拿综合榜榜一 Java内容榜第二 总之谢谢大家支持 小苏会继续努力的 可以看看我的新作 嘻嘻&#x1f601;&#x1f924;&#x1f449;&#x1f3fb;&#x1f448;&#x1f3fb; 谢谢大家

web3知识体系汇总

web3.0知识体系 1.行业发展 2. web3的特点&#xff1a; 1、统一身份认证系统 2、数据确权与授权 3、隐私保护与抗审查 4、去中心化运行 Web3.0思维技术思维✖金融思维✖社群思维✖产业思维”&#xff0c;才能从容理解未来Web3.0时代的大趋势。 3.技术栈 Web3.jsSolidit…

Spring Boot 笔记 005 环境搭建

1.1 创建数据库和表&#xff08;略&#xff09; 2.1 创建Maven工程 2.2 补齐resource文件夹和application.yml文件 2.3 porn.xml中引入web,mybatis,mysql等依赖 2.3.1 引入springboot parent 2.3.2 删除junit 依赖--不能删&#xff0c;删了会报错 2.3.3 引入spring web依赖…

2.14数据结构与算法学习日记

洛谷P1934 封印 题目背景 很久以前&#xff0c;魔界大旱&#xff0c;水井全部干涸&#xff0c;温度也越来越高。为了拯救居民&#xff0c;夜叉族国王龙溟希望能打破神魔之井&#xff0c;进入人界“窃取”水灵珠&#xff0c;以修复大地水脉。可是六界之间皆有封印&#xff0c;…

洛谷_P1059 [NOIP2006 普及组] 明明的随机数_python写法

这道题的关键在于去重和排序&#xff0c;去重可以联想到集合&#xff0c;那排序直接使用sort方法。 n int(input()) data set(map(int,input().split( ))) data list(data) data.sort() print(len(data)) for i in data:print(i,end )

Python编程之旅:从入门到精通

在数字世界的无尽宇宙中&#xff0c;Python无疑是一颗璀璨的明星。其简洁易懂的语法、丰富的库和广泛的应用领域&#xff0c;使得Python成为了众多初学者的首选编程语言。那么&#xff0c;如何学习Python呢&#xff1f;本文将带你一步步踏上Python编程的旅程。 一、入门篇&…

1.Electron初始与安装

这里写目录标题 一、前言二、下载三、简要总结 一、前言 原文以及该系列后续文章请参考&#xff1a;安装Electron 随着前端的不断强盛&#xff0c;现在的前端已经不再满足于网页开发了&#xff0c;而是在尝试能否使用前端的开发逻辑来开发PC端的桌面软件。 即用html、js、css…

软件价值12-射箭游戏

射箭游戏&#xff0c;按空格键发射&#xff0c;打击移动靶&#xff0c;左上角显示成绩状态。 代码&#xff1a; import pygame import sys import random# 初始化Pygame pygame.init()# 设置窗口大小 SCREEN_WIDTH 800 SCREEN_HEIGHT 600 screen pygame.display.set_mode((…

leetcode:55.跳跃游戏

1.解题思路&#xff1a;贪心算法看最大覆盖范围 2.模拟过程&#xff1a; 1.若数组长度等于1&#xff0c;直接返回True 2.循环遍历覆盖范围&#xff0c;选取最大的覆盖范围&#xff1b;若覆盖范围覆盖到了最后一个元素&#xff0c;直接返回true. 3.代码&#xff1a;(贪心无套…

蓝牙BLE学习-蓝牙广播

1.概念 什么叫做广播&#xff0c;顾名思义就像广场上的大喇叭一样&#xff0c;不停的向外传输着信号。不同的是&#xff0c;大喇叭传输的是音频信号&#xff0c;而蓝牙传输的是射频信号。 BLE使用的是无线电波传递信息&#xff0c;就是将数据编码&#xff0c;调制到射频信号中发…

Node.js开发-HTTP协议

HTTP协议 1) 概念2) 请求报文的组成3) HTTP 的请求行4) HTTP 请求头5) HTTP 的请求体6) 响应报文的组成7) 创建 HTTP 服务8) 获取 HTTP请求报文9) 设置 HTTP 响应报文10) 设置资源类型&#xff08;mime类型&#xff09;11) GET和POST请求的区别 1) 概念 HTTP&#xff08;hyper…