无重复字符的最长子串[中等]

优质博文:IT-BLOG-CN
在这里插入图片描述

一、题目

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

示例 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由英文字母、数字、符号和空格组成

二、代码

方案一

思路:
【1】通过hashMap[key = val , value = index]存放字符串中的字母;
【2】当有重复字母出现时,将left指向重复字母最左边的下标;
【3】最后通过i = left获取下标与left取最大值;

/**
 * 思路:1、通过hashMap[key = val , value = index]存放字符串中的字母;
 *       2、当有重复字母出现时,将 left 指向重复字母最左边的下标;
 *       3、最后通过 i = left 获取下标 与 left取最大值;
 */
class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character,Integer> map = new HashMap();
        int left = 0;
        int max = 0;
        if (s.length() == 0) return 0;
        
        for (int i = 0; i < s.length(); i++) {
            if (map.containsKey(s.charAt(i))) {
                left = Math.max(left, map.get(s.charAt(i)) + 1);
            }
            map.put(s.charAt(i), i);
            max = Math.max(max, i - left + 1);
        }
        return max;
    }
}

方案二

思路: 方案一时左指针基本不动,右指针遍历。方案二是左指针遍历,右指针基本不动。
通过HashSet对记录字符串,包含时计算长度,并对右指针进行偏移,如果不包含则偏移左指针。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        // 哈希集合,记录每个字符是否出现过
        Set<Character> occ = new HashSet<Character>();
        int n = s.length();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int rk = -1, ans = 0;
        for (int i = 0; i < n; ++i) {
            if (i != 0) {
                // 左指针向右移动一格,移除一个字符
                occ.remove(s.charAt(i - 1));
            }
            while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
                // 不断地移动右指针
                occ.add(s.charAt(rk + 1));
                ++rk;
            }
            // 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = Math.max(ans, rk - i + 1);
        }
        return ans;
    }
}

复杂度分析: O(N)其中N是字符串的长度。左指针和右指针分别会遍历整个字符串一次。
空间复杂度: O(∣Σ∣)其中Σ表示字符集(即字符串中可以出现的字符),∣Σ∣|表示字符集的大小。在本题中没有明确说明字符集,因此可以默认为所有ASCII码在[0,128)内的字符,即∣Σ∣=128。我们需要用到哈希集合来存储出现过的字符,而字符最多有∣Σ∣个,因此空间复杂度为O(∣Σ∣)

方案三:滑动窗口

我们先用一个例子考虑如何在较优的时间复杂度内通过本题。

我们不妨以示例一中的字符串abcabcbb为例,找出从每一个字符开始的,不包含重复字符的最长子串,那么其中最长的那个字符串即为答案。对于示例一中的字符串,我们列举出这些结果,其中括号中表示选中的字符以及最长的字符串:

(a)bcabcbb开始的最长字符串为(abc)abcbb
a(b)cabcbb开始的最长字符串为a(bca)bcbb
ab(c)abcbb开始的最长字符串为ab(cab)cbb
abc(a)bcbb开始的最长字符串为abc(abc)bb
abca(b)cbb开始的最长字符串为abca(bc)bb
abcab(c)bb开始的最长字符串为abcab(cb)b
abcabc(b)b开始的最长字符串为abcabc(b)b
abcabcb(b)开始的最长字符串为abcabcb(b)

发现了什么?如果我们依次递增地枚举子串的起始位置,那么子串的结束位置也是递增的!这里的原因在于,假设我们选择字符串中的第k个字符作为起始位置,并且得到了不包含重复字符的最长子串的结束位置为rk。那么当我们选择第k+1个字符作为起始位置时,首先从k+1rk的字符显然是不重复的,并且由于少了原本的第k个字符,我们可以尝试继续增大rk,直到右侧出现了重复字符为止。

这样一来,我们就可以使用「滑动窗口」来解决这个问题了:

我们使用两个指针表示字符串中的某个子串(或窗口)的左右边界,其中左指针代表着上文中「枚举子串的起始位置」,而右指针即为上文中的rk

在每一步的操作中,我们会将左指针向右移动一格,表示 我们开始枚举下一个字符作为起始位置,然后我们可以不断地向右移动右指针,但需要保证这两个指针对应的子串中没有重复的字符。在移动结束后,这个子串就对应着 以左指针开始的,不包含重复字符的最长子串。我们记录下这个子串的长度;

在枚举结束后,我们找到的最长的子串的长度即为答案。

**判断重复字符:**在上面的流程中,我们还需要使用一种数据结构来判断 是否有重复的字符,常用的数据结构为哈希集合。在左指针向右移动的时候,我们从哈希集合中移除一个字符,在右指针向右移动的时候,我们往哈希集合中添加一个字符。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        // 哈希集合,记录每个字符是否出现过
        Set<Character> occ = new HashSet<Character>();
        int n = s.length();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int rk = -1, ans = 0;
        for (int i = 0; i < n; ++i) {
            if (i != 0) {
                // 左指针向右移动一格,移除一个字符
                occ.remove(s.charAt(i - 1));
            }
            while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
                // 不断地移动右指针
                occ.add(s.charAt(rk + 1));
                ++rk;
            }
            // 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = Math.max(ans, rk - i + 1);
        }
        return ans;
    }
}

时间复杂度: O(N),其中N是字符串的长度。左指针和右指针分别会遍历整个字符串一次。
空间复杂度: O(∣Σ∣),其中Σ表示字符集(即字符串中可以出现的字符),∣Σ∣表示字符集的大小。在本题中没有明确说明字符集,因此可以默认为所有ASCII码在[0,128)内的字符,即∣Σ∣=128。我们需要用到哈希集合来存储出现过的字符,而字符最多有∣Σ∣个,因此空间复杂度为O(∣Σ∣)

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

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

相关文章

Verilog刷题笔记17

题目&#xff1a; For hardware synthesis, there are two types of always blocks that are relevant: Combinational: always (*) Clocked: always (posedge clk) Clocked always blocks create a blob of combinational logic just like combinational always blocks, but …

el-table中设置第一列为多选框,且多选框动态禁用

给el-table第一列写成以下代码: <el-table-columntype"selection"width"55"></el-table-column> 效果: 多选框动态禁用 el-table中设置了 type"selection"&#xff0c;但是由于部分数据是已经处理过的&#xff0c;不允许选中&…

css-盒子等样式学习

盒子居中&#xff0c;继承外层盒子的宽高 兼容性&#xff08;border-box&#xff09;将边框收到盒子内部 初始化div 不用管box-setting content-box 还原 创建为一个类 &#xff0c;让所有需要还原的类 进行继承 padding 用法表示margin上下左右边距 body 外边距&…

高性价比低功耗高性能蓝牙5.2系统级芯片PHY6230

PHY6230 是一款高性价比低功耗高性能Bluetooth LE 5.2系统级芯片&#xff0c;集成32-bit高性能低功耗MCU&#xff0c;16KB OTP&#xff0c;8KB Retention SRAM和64KB ROM&#xff0c;可选EEPROM。内置高性能多模射频收发机最大发射功率10dBm&#xff0c;BLE 1Mbps速率下接收灵敏…

最新 生成pdf文字和表格

生成pdf文字和表格 先看效果 介绍 java项目&#xff0c;使用apache的pdfbox工具&#xff0c;可分页&#xff0c;自定义列 依赖 <dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.22<…

5-微信小程序语法参考

1. 数据绑定 官网传送门 WXML 中的动态数据均来自对应 Page 的 data。 数据绑定使用 Mustache 语法&#xff08;双大括号&#xff09;将变量包起来 ts Page({data: {info: hello wechart!,msgList: [{ msg: hello }, { msg: wechart }]}, })WXML <view class"vie…

Nodejs 第三十二章(数据库)

MySQL是一种开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是最受欢迎的数据库系统之一。MySQL广泛用于Web应用程序和其他需要可靠数据存储的应用程序中。 以下是MySQL数据库的一些重要特点和概念&#xff1a; 数据库&#xff1a;MySQL是一个数据库…

Oracle21C + PLSQL Developer 15 + Oracle客户端21安装配置完整图文版

一、Oracle21C PLSQL Developer 15 Oracle客户端文件下载 1、Oracl21C下载地址&#xff1a;Database Software Downloads | Oracle 中国 2、 PLSQL Developer 15下载地址&#xff1a;Registered download PL/SQL Developer - Allround Automations 3、 Oracle 客户端下载地址…

【linux驱动】用户空间程序与内核模块交互-- IOCTL和Netlink

创建自定义的IOCTL&#xff08;输入/输出控制&#xff09;或Netlink命令以便用户空间程序与内核模块交互涉及几个步骤。这里将分别介绍这两种方法。 一、IOCTL 方法 1. 定义IOCTL命令 在内核模块中&#xff0c;需要使用宏定义你的IOCTL命令。通常情况下&#xff0c;IOCTL命令…

RHCE9学习指南 第21章 用bash写脚本

grep的用法是&#xff1a; grep 关键字 file 意思是从file中过滤出含有关键字的行。 例如&#xff0c;grep root /var/log/messages&#xff0c;意思是从/var/log/messages中过滤出含有root的行。这里很明确的是过滤含有“root”的行。 如果我要是想在/var/log/messages中过滤…

IPv6自动隧道---6to4隧道

IPv6 over IPv4自动隧道特点 由于IPv4兼容IPv6隧道要求每一个主机都要有一个合法的IP地址,而且通讯的主机要支持双栈、支持IPv4兼容IPv6隧道,不适合大面积部署。目前该技术已经被6to4隧道所代替。 6to4隧道 集手动隧道和自动隧道的优点于一身,提出6to4的目的是为IPv4网络…

git 常规操作及设置

git 常规操作及设置 Git是一个分布式版本控制系统&#xff0c;可以用来跟踪文件的修改历史并与其他人进行协作开发。下面是一些常见的Git操作及设置&#xff1a; 初始化仓库&#xff1a;使用命令git init在当前目录创建一个新的Git仓库。 克隆仓库&#xff1a;使用命令git clo…

web terminal - 如何在mac os上运行gotty

gotty可以让你使用web terminal的方式与环境进行交互&#xff0c;实现终端效果 假设你已经配置好了go环境&#xff0c;首先使用go get github.com/yudai/gotty命令获取可执行文件&#xff0c;默认会安装在$GOPATH/bin这个目录下&#xff0c;注意如果你的go版本比较高&#xff…

【elementUI】el-select相关问题

官方使用DEMO <template><el-select v-model"value" placeholder"请选择"><el-optionv-for"item in options":key"item.value":label"item.label":value"item.value"></el-option></…

CTF CRYPTO 密码学-4

题目名称&#xff1a;奇怪的先生 题目描述&#xff1a; 描述:oss先生将三个培根的中间一只移到了左边,然后咬了一小口最后一根&#xff0c;说真好吃&#xff0c;真是个奇怪的先生&#xff01; 密文&#xff1a;VlM5WnlXc0ZibEhmMmE1ZHYxMDlhVkdmMlk5WmtRPT0 分析 应该是根据题…

Firefox 100 正式发布

五月三日&#xff0c;Firefox发布了它的第100个版本&#xff0c;来回顾一下Firefox是如何走到今天这一步的&#xff0c;以及在第100个版本中发布了哪些功能。 回顾 2004年&#xff0c;《纽约时报》上宣布了Firefox 1.0的发布&#xff0c;这个广告列出了为第一版做出贡献的每一…

物联网中的通信技术

阅读引言&#xff1a; 本文主要大致为大家带来物联网中的常见的通信方式的知识梳理。 目录 一、概述 二、无线通信技术 1.物联网电子标签 RFID 1.1 RFID 概念 1.2 RFID 系统组成 2.WI-FI技术 3.UWB技术 4.ZigBee技术 5.NFC技术 6.蓝牙技术 7.EnOcean技术 一、概述 物…

Spring06

一、SpirngMvc的基本概念 Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架&#xff0c;本质上相当于 Servlet。 MVC&#xff08;Model View Controller&#xff09;&#xff0c;一种用于设计创建Web应用程序的开发模式 Model&#xff08;模型&#xff…

苹果电脑(Mac)的node版本安装以及升降级

在开发过程中&#xff0c;对于不同的开发环境或者较老的项目可能需要切换不同的node版本&#xff0c;此过程会涉及到node版本的升级与降级&#xff0c;安装node版本管理模块n&#xff08;sudo命令&#xff09;。 全局安装n模块 sudo npm install n -g//输入后回车&#xff0c…

自动驾驶轨迹规划之碰撞检测(三)

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.基于圆覆盖 2.BVH 3.MATLAB自动驾驶工具箱 4 ROS内置的模型 自动驾驶轨迹规划之碰撞检测&#xff08;一&#xff09;-CSDN博客 自动驾…