【力扣算法日记】无重复字符的最长子串

news2024/12/23 22:12:47

最近刷了很多算法题,这些解题过程也拓展了自己的思路,是个适合记录的素材。所以决定在继技术知识点详解的【一文系列】之后,开启新坑——【力扣算法系列】,来记录力扣刷题过程。

分享题目不确定,目前打算只分享我认为值得分享的题目,或者你们有什么想要我分享的题目,我愿意去研究透彻之后出分析详解!分享的过程也是自我学习的过程!

leetCode

那么今天,我们分享第一道题目:无重复字符的最长子串

题目

无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

来源:https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/

示例 1:

输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:

输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:

输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成


解题

暴力法

这是最容易想到的方法,当然也是最废的方法。不过我们在解题的时候,可以先尝试暴力解法,然后再一步步着手优化,或想出更好的方法,这也是一种解题思路。在这道题目中,暴力解法就是逐个检查所有的子字符串,看它是否不含有重复的字符。

public static int lengthOfLongestSubstring(String s) {
    char[] chars = s.toCharArray();
    Map<Character, Integer> subChars = new HashMap<Character, Integer>(chars.length);
    int maxSize = 0;
    int repeatIndex = -1;
    int i = 0;
    while (i < chars.length) {
        for (int j = i; j < chars.length; j++) {
            char c = chars[j];
            if (subChars.containsKey(c)) {
                repeatIndex = subChars.get(c);
                break;
            }
            subChars.put(c, j);
        }
        if (repeatIndex != -1) {
            // 找到重复元素,从第一个重复元素的下一个下标开始遍历
            i = repeatIndex + 1;
            repeatIndex = -1;
        } else {
            i++;
        }
        maxSize = Math.max(maxSize, subChars.size());
        subChars.clear();
        float middleSize = chars.length / 2f;
        if (maxSize >= middleSize && i >= middleSize) {
            // 最大子串长度超过一半了,可以不用继续遍历了
            break;
        }
    }
    return maxSize;
}

滑动窗口

滑动窗口是字符串类问题的最常用的方法。在这道题目中,我们按区间进行字符串搜索,遇到重复字符,就从左区间开始删除,直到删除掉重复字符为止。

在这道题目中,滑动窗口其实相当于就是一个队列,比如例题中的 abcabcbb:

  1. 进入这个队列(窗口)为 abc,暂时满足题目要求
    滑动窗口

  2. 当再进入 a,队列变成了 abca
    滑动窗口

  3. 这时候不满足要求,所以,我们要移动这个队列,把队列的左边的元素移出就行了,一直到满足题目要求。
    滑动窗口

一直维持这样的队列,找出队列出现最长的长度时候,我们就求得最终答案。

public int lengthOfLongestSubstring(String s) {
    int len = s.length();
    // 最大长度
    int maxLength = 0;
    // 左指针
    int left = 0;
    // 右指针
    int right = 0;
    // 子串队列
    Set<Character> subChars = new HashSet<>();
    while (left < len && right < len) {
        if (subChars.contains(s.charAt(right))) {
            // 子串重复,字符串从队首开始移除
            subChars.remove(s.charAt(left));
            // 移动左指针
            left++;
        } else {
            // 子串不重复,字符入队尾
            subChars.add(s.charAt(right));
            right++;
            // 记录最长不重复长度
            maxLength = Math.max(maxLength, right - left);
        }
    }
    return maxLength;
}

优化的滑动窗口

在滑动窗口时,上述的方法最多需要执行 2n 个步骤。事实上,它可以被进一步优化为仅需要 n 个步骤。我们可以定义字符到索引的映射,而不是使用集合来判断一个字符是否存在。 当我们找到重复的字符时,我们可以立即跳过该窗口。

public static int lengthOfLongestSubstring(String s) {
    int len = s.length();
    // 最大长度
    int maxLength = 0;
    // 使用Map结构缓存字符和索引的映射
    Map<Character, Integer> map = new HashMap<>();
    // 滑动窗口
    for (int right = 0, left = 0; right < len; right++) {
        char c = s.charAt(right);
        if (map.containsKey(c)) {
            // 找到重复子串,左指针跳到最后的重复位置
            left = Math.max(map.get(c), left);
        }
        int curLength = right - left + 1;
        // 取最大长度
        maxLength = Math.max(maxLength, curLength);
        // 缓存字符和下标映射
        map.put(c, right + 1);
    }
    return maxLength;
}

优化的滑动窗口2

针对上述优化方式,我们还可以进一步优化,不过这个方法相对有些投机取巧,各位看看就行

public static int lengthOfLongestSubstring(String s) {
//      Java(假设字符集为 ASCII 128)
//      以前我们没有对字符串 s 所使用的字符集进行假设。
//      当我们知道该字符集比较小的时侯,我们可以用一个整数数组作为直接访问表来替换 Map。
    int len = s.length();
    // 最大长度
    int maxLength = 0;
    // 使用128位数组缓存下标
    int[] index = new int[128];
    // 滑动窗口
    for (int right = 0, left = 0; right < len; right++) {
        char c = s.charAt(right);
        // 取index对应字符的缓存下标
        // 如果没有,则是默认值0
        // 若一旦有非零值,则代表有相同字符缓存到index数组中,则下标可跳到最后重复为止,再计算出不重复长度
        left = Math.max(index[c], left);
        int curLength = right - left + 1;
        // 取最大长度
        maxLength = Math.max(maxLength, curLength);
        // 缓存字符和下标映射
        index[c] = right + 1;
    }
    return maxLength;
}

这道题的解法中,暴力解法一定是不可取的,其实能写出滑动窗口解法就差不多了,优化方式都是加分项了。当然了,解题方法一定不止于此,大家可以继续深究!


更多技术干货,欢迎关注我!

qr

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

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

相关文章

聊一聊 .NET高级调试 内核模式堆泄露

一&#xff1a;背景 1. 讲故事 前几天有位朋友找到我&#xff0c;说他的机器内存在不断的上涨&#xff0c;但在任务管理器中查不出是哪个进程吃的内存&#xff0c;特别奇怪&#xff0c;截图如下&#xff1a; 在我的分析旅程中都是用户态模式的内存泄漏&#xff0c;像上图中的…

【JVM】类加载器ClassLoader

一、简介 在Java中&#xff0c;类加载器&#xff08;ClassLoader&#xff09;是一个关键的组件&#xff0c;它负责将字节码文件加载到内存并转换成Java类。Java的类加载器主要可以分成两类&#xff1a;系统提供的和由Java应用开发人员编写的。Java开发者可以根据需要创建自己的…

ES集群分片数据的高可用

文章目录 ES集群分片数据的高可用1. 集群设置索引节点2. 集群新增文档数据3.查看集群中文档数据分片节点4. 让节点9201宕机&#xff0c;查看其分片变化5. 让节点9201&#xff0c;查看分片变化 ES集群分片数据的高可用 集群中的索引主分片和副分片在不同的计算机上&#xff0c;如…

揭开 JavaScript 作用域的神秘面纱(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

pyqtgraph 教程

pyqtgraph 教程 简介 PyQtGraph 是一个用于科学和工程数据可视化的开源库&#xff0c;基于 PyQt 和 NumPy 构建而成。它提供了丰富的绘图工具和交互功能&#xff0c;可以用于创建高性能的实时数据图表、图像显示和信号处理应用。 以下是 PyQtGraph 的一些特点和功能&#xf…

.NET Standard 支持的 .NET Framework 和 .NET Core

.NET Standard 是针对多个 .NET 实现推出的一套正式的 .NET API 规范。 推出 .NET Standard 的背后动机是要提高 .NET 生态系统中的一致性。 .NET 5 及更高版本采用不同的方法来建立一致性&#xff0c;这种方法在大多数情况下都不需要 .NET Standard。 但如果要在 .NET Framewo…

基于sumo实现交通灯控制算法的模板

基于sumo实现交通灯控制算法的模板 目录 在windows安装run hello world networkroutesviewsettings & configurationsimulation 交通灯控制系统 介绍文件生成器类&#xff08;FileGenerator&#xff09;道路网络&#xff08;Network&#xff09;辅助函数生成道路网络&am…

从细菌基因组中提取噬菌体变异序列工具PhaseFinder的介绍、安装和使用方法

PhaseFinder ## 概览&#xff0c;不翻译了&#xff0c;大家自己看吧 The PhaseFinder algorithm is designed to detect DNA inversion mediated phase variation in bacterial genomes using genomic or metagenomic sequencing data. It works by identifying regions flank…

Java学习笔记(四)——正则表达式

文章目录 正则表达式基本规则字符类(只匹配一个字符)预定义字符(只匹配一个字符)数量词练习正则表达式插件 爬虫利用正则表达式获取想要的内容爬取网络信息练习有条件的爬取贪婪爬取非贪婪爬取正则表达式在字符串中的使用 分组捕获分组正则表达式外部使用非捕获分组正则表达式忽…

公共用例库计划--个人版(二)主体界面设计

1、任务概述 计划内容&#xff1a;完成公共用例库的开发实施工作&#xff0c;包括需求分析、系统设计、开发、测试、打包、运行维护等工作。 1.1、 已完成&#xff1a; 需求分析、数据库表的设计&#xff1a;公共用例库计划–个人版&#xff08;一&#xff09; 1.2、 本次待…

神经网络-卷积层

卷积 输入通道数&#xff0c; 输出通道数&#xff0c;核大小 参数具体含义 直观理解各个参数的网站(gif) https://github.com/vdumoulin/conv_arithmetic/blob/master/README.md大概长这样&#xff0c;cyan是青色的意思 channel数&#xff08;终于理解论文里图片放好多层的原因…

VMware ESXI 8 安装ipmitool 调整戴尔服务器风扇转速

本文内容适合ESXI 8版本安装ipmitool &#xff0c;进行管理&#xff0c;已知的是8.0以上版本无法安装社区的vib.所以需要自己编译文件&#xff0c;7.0及之前的版本可以安装vib版本的ipmtools。 一、编译好的适用于esxi8的ipmitool下载 ipmitool下载 二、安装ipmitool 1、开…

铁塔基站数字化管理监测解决方案

截至2023年10月&#xff0c;我国5G基站总数达321.5万个&#xff0c;占全国通信基站总数的28.1%。然而&#xff0c;随着5G基站数量的快速增长&#xff0c;基站的能耗问题也逐渐日益凸显&#xff0c;基站的用电给运营商带来了巨大的电费开支压力&#xff0c;降低5G基站的能耗成为…

new FormData 同时发送表单 json 以及文件二进制流

需要新增时同时发送表单 json 以及对应的文件即可使用以下方法传参 let formDataParams new FormData(); 首先通过 new FormData&#xff08;&#xff09; 创建你需要最后发送的表单 接着将你的对象 json 存储&#xff0c;注意使用 new Blob 创建大表单转换成 json 格式。以…

根据MySql的表名,自动生成实体类,模仿ORM框架

ORM框架可以根据数据库的表自动生成实体类&#xff0c;以及相应CRUD操作 本文是一个自动生成实体类的工具&#xff0c;用于生成Mysql表对应的实体类。 新建Winform窗体应用程序AutoGenerateForm&#xff0c;框架(.net framework 4.5)&#xff0c; 添加对System.Configuration的…

了解nginx

1&#xff0c;概念 nginx是一个轻量级、高性能的HTTP和反向代理web服务器&#xff0c;同时也是一个通用代理服务器&#xff08;TCP、UDP、IMAP、POP3、SMTP&#xff09;。 2&#xff0c;优势 轻量级&#xff0c;占用内存少&#xff0c;启动极快采用事件驱动的异步非阻塞处理方…

linux中的系统安全

一.账号安全 将非登录用户的shell设为/sbin/nologin 系统中用户有三种&#xff1a;超级管理员 普通用户 程序用户 前两种用户可以登录系统&#xff0c;程序用户不给登录 所以称为非登录用户 命令格式&#xff1a; usermod -s /sbin/nologin&#xff08;改已有用户&#…

亲测表白网制作源码,在线制作表白,无数据库上传就能用

在线制作表白网源码 没有数据库上传就能用 后台/admin 账号密码都是admin

【mars3d】批量关闭矢量数据的startFlicker()闪烁或者全部关闭startFlicker()

问题 1.graphic/entity/billboard怎么能够批量关闭startFlicker()闪烁或者 全部关闭startFlicker()呢&#xff1f; 相关链接 1.http://mars3d.cn/editor-vue.html?idgraphic/entity/billboard 2.http://mars3d.cn/apidoc.html#FlickerEntity 期望效果 1.graphic.stopFlic…

Java:爬虫htmlunit

为什么htmlunit与HttpClient两者都可以爬虫、网页采集、通过网页自动写入数据&#xff0c;我们会推荐使用htmlunit呢? 一、网页的模拟化 首先说说HtmlUnit相对于HttpClient的最明显的一个好处&#xff0c;HtmlUnit更好的将一个网页封装成了一个对象&#xff0c;如果你非要说H…