leetcode 面试经典 150 题:无重复字符的最长子串

链接无重复字符的最长子串
题序号3
类型字符串
解题方法滑动窗口
难度中等

题目

给定一个字符串 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. 核心要点:这个问题可以通过滑动窗口的方法来解决。滑动窗口表示当前考虑的子串的范围,我们通过移动窗口的边界来找到不含有重复字符的最长子串。

    • 初始化:定义两个指针 left 和 right 分别表示窗口的左右边界,以及一个哈希表 char_index_map 来存储字符及其索引。
    • 扩展窗口:将 right 指针向右移动,扩展窗口,直到遇到重复的字符。
    • 更新最大长度:在每次移动 right 指针时,更新不含有重复字符的子串的最大长度。
    • 收缩窗口:当遇到重复的字符时,移动 left 指针,收缩窗口,直到重复的字符被移出窗口。
    • 重复步骤2-4:直到 right 指针到达字符串的末尾。
  2. 时间复杂度: O(n)

  3. 空间复杂度:O(n)

  4. c++ 实现算法

class Solution {
public:
    int lengthOfLongestSubstring(string s) {

        unordered_map<char, int> map; // 哈希表记录字符的最新索引,map 的键是字符,值是该字符的最后出现的索引位置
        int max_len = 0; // 最长子串长度
        int left = 0; // 滑动窗口的左边界

        for (int right = 0; right < s.size(); ++right) {

            // 如果当前字符在窗口内出现过,更新窗口的左边界
            //如果 map.find(s[right]) 返回的不是 map.end(),意味着哈希表中存在字符 s[right],
            //也就是说,字符 s[right] 在哈希表中出现过。
            
            //如果返回 map.end(),则说明哈希表中没有这个字符,即字符 s[right] 没有在哈希表中出现过。
            //map[s[right]] >= left,字符 s[right] 在窗口中的 上一次出现的位置 
            //大于等于当前窗口的左边界 left,那么就说明它是重复的。
            if (map.find(s[right]) != map.end() && map[s[right]] >= left) {
                //将 left 更新为字符 s[right] 最新出现位置的下一个位置
                left = map[s[right]] + 1;
            }
            
            // 更新当前字符的最新位置
            map[s[right]] = right;
            
            // 计算当前窗口的大小,更新最大长度
            max_len = max(max_len, right - left + 1);
        }

        return max_len;
    }
};
  1. 演示:以示例1为例

遍历字符串 s,right 从 0 到 7:

  1. right = 0,字符 ‘a’: map.find(s[right]) != map.end() 检查字符 ‘a’ 是否已经出现过。由于 map 为空,所以字符 ‘a’ 不在其中。 更新哈希表:map[‘a’] = 0。字符 ‘a’ 的最新索引是 0。计算当前窗口大小:right - left + 1 = 0 - 0 + 1 = 1。 更新 max_len:max_len = max(0,1) = 1。

  2. right = 1,字符 ‘b’: map.find(s[right]) != map.end() 检查字符 ‘b’ 是否已经出现过。字符 ‘b’ 不在哈希表中。 更新哈希表:map[‘b’] = 1。字符 ‘b’ 的最新索引是 1。计算当前窗口大小:right - left + 1 = 1 - 0 + 1 = 2。 更新 max_len:max_len = max(1, 2) = 2。

  3. right = 2,字符 ‘c’: map.find(s[right]) != map.end() 检查字符 ‘c’ 是否已经出现过。字符 ‘c’ 不在哈希表中。 更新哈希表:map[‘c’] = 2。字符 ‘c’ 的最新索引是 2。计算当前窗口大小:right - left + 1 = 2 - 0 + 1 = 3。 更新 max_len:max_len = max(2, 3) = 3。

  4. right = 3,字符 ‘a’: map.find(s[right]) != map.end() 检查字符 ‘a’ 是否已经出现过。字符 ‘a’ 已经在 map 中,且它的索引是 0(小于 right = 3)。 由于 ‘a’ 重复了,我们需要更新滑动窗口的左边界: left = map[‘a’] + 1 = 0 + 1 = 1,新的左边界是 1,即跳过 a 在左边的位置。 更新哈希表:map[‘a’] = 3。字符 ‘a’ 的最新索引是 3。 计算当前窗口大小:right - left + 1 = 3 - 1 + 1 = 3。 max_len 仍然是 3(不更新)。

  5. right = 4,字符 ‘b’: map.find(s[right]) != map.end() 检查字符 ‘b’ 是否已经出现过。字符 ‘b’ 已经在 map 中,且它的索引是 1(小于 right = 4)。 由于 ‘b’ 重复了,我们需要更新滑动窗口的左边界: left = map[‘b’] + 1 = 1 + 1 = 2,新的左边界是 2,即跳过 b 在左边的位置。 更新哈希表:map[‘b’] = 4。字符 ‘b’ 的最新索引是 4。 计算当前窗口大小:right - left + 1 = 4 - 2 + 1 = 3。 max_len 仍然是 3(不更新)。

  6. right = 5,字符 ‘c’: map.find(s[right]) != map.end() 检查字符 ‘c’ 是否已经出现过。字符 ‘c’ 已经在 map 中,且它的索引是 2(小于 right = 5)。 由于 ‘c’ 重复了,我们需要更新滑动窗口的左边界: left = map[‘c’] + 1 = 2 + 1 = 3,新的左边界是 3,即跳过 c 在左边的位置。 更新哈希表:map[‘c’] = 5。字符 ‘c’ 的最新索引是 5。 计算当前窗口大小:right - left + 1 = 5 - 3 + 1 = 3。 max_len 仍然是 3(不更新)。

  7. right = 6,字符 ‘b’: map.find(s[right]) != map.end() 检查字符 ‘b’ 是否已经出现过。字符 ‘b’ 已经在 map 中,且它的索引是 4(小于 right = 6)。 由于 ‘b’ 重复了,我们需要更新滑动窗口的左边界: left = map[‘b’] + 1 = 4 + 1 = 5,新的左边界是 5,即跳过 b在左边的位置。 更新哈希表:map[‘b’] = 6。字符 ‘b’ 的最新索引是 6。 计算当前窗口大小:right - left + 1 = 6 - 5 + 1 = 2。 max_len 仍然是 3(不更新)。

  8. right = 7,字符 ‘b’: map.find(s[right]) != map.end() 检查字符 ‘b’ 是否已经出现过。字符 ‘b’ 已经在 map 中,且它的索引是 6(小于 right = 7)。 由于 'b’重复了,我们需要更新滑动窗口的左边界: left = map[‘b’] + 1 = 6 + 1 = 7,新的左边界是 7,即跳过 b 在左边的位置。 更新哈希表:map[‘b’] = 7。字符 ‘b’ 的最新索引是 7。 计算当前窗口大小:right - left + 1 = 7 - 7 + 1 = 1。 max_len 仍然是 3(不更新)。

  1. c++ demo
#include <iostream>
#include <unordered_map>
#include <algorithm>
using namespace std;

class Solution {
public:
    int lengthOfLongestSubstring(string s) {

        unordered_map<char, int> map; // 哈希表记录字符的最新索引,map 的键是字符,值是该字符的最后出现的索引位置
        int max_len = 0; // 最长子串长度
        int left = 0; // 滑动窗口的左边界

        for (int right = 0; right < s.size(); ++right) {

            // 如果当前字符在窗口内出现过,更新窗口的左边界
            //如果 map.find(s[right]) 返回的不是 map.end(),意味着哈希表中存在字符 s[right],
            //也就是说,字符 s[right] 在哈希表中出现过。
            
            //如果返回 map.end(),则说明哈希表中没有这个字符,即字符 s[right] 没有在哈希表中出现过。
            //map[s[right]] >= left,字符 s[right] 在窗口中的 上一次出现的位置 
            //大于等于当前窗口的左边界 left,那么就说明它是重复的。
            if (map.find(s[right]) != map.end() && map[s[right]] >= left) {
                //将 left 更新为字符 s[right] 最新出现位置的下一个位置
                left = map[s[right]] + 1;
            }
            
            // 更新当前字符的最新位置
            map[s[right]] = right;
            
            // 计算当前窗口的大小,更新最大长度
            max_len = max(max_len, right - left + 1);
        }

        return max_len;
    }
};

int main() {
    Solution sol;
    string s = "abcabcbb";
    cout << "The length of the longest substring without repeating characters is: " 
         << sol.lengthOfLongestSubstring(s) << endl;
    return 0;
}

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

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

相关文章

前端知识补充—HTML

1. HTML 1.1 什么是HTML HTML(Hyper Text Markup Language), 超⽂本标记语⾔ 超⽂本: ⽐⽂本要强⼤. 通过链接和交互式⽅式来组织和呈现信息的⽂本形式. 不仅仅有⽂本, 还可能包含图⽚, ⾳频, 或者⾃已经审阅过它的学者所加的评注、补充或脚注等等 标记语⾔: 由标签构成的语⾔…

vscode 使用说明

文章目录 1、文档2、技巧显示与搜索宏定义和包含头文件 3、插件4、智能编写5、VSCode 与 C&#xff08;1&#xff09;安装&#xff08;2&#xff09;调试&#xff08;a&#xff09;使用 CMake 进行跨平台编译与调试&#xff08;b&#xff09;launch.json&#xff08;c&#xff…

Python的3D可视化库【vedo】2-5 (plotter模块) 坐标转换、场景导出、添加控件

文章目录 4 Plotter类的方法4.7 屏幕和场景中的坐标点转换4.7.1 屏幕坐标转为世界坐标4.7.2 世界坐标转为屏幕坐标4.7.3 屏幕坐标取颜色 4.8 导出4.8.1 导出2D图片4.8.2 导出3D文件 4.9 添加控件4.9.1 添加内嵌子窗口4.9.2 添加选择区4.9.3 添加比例尺4.9.4 为对象添加弹出提示…

Gin-vue-admin(1):环境配置和安装

目录 环境配置如果443网络连接问题&#xff0c;需要添加代理服务器 后端运行前端运行 环境配置 git clone https://gitcode.com/gh_mirrors/gi/gin-vue-admin.git到server文件目录下 go mod tidygo mod tidy 是 Go 语言模块系统中的一个命令&#xff0c;用于维护 go.mod 文件…

【CSS in Depth 2 精译_088】第五部分:添加动效概述 + 第 15 章:CSS 过渡特效概述 + 15.1:状态间的由此及彼

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第五部分 添加动效 ✔️【第 15 章 过渡】 ✔️ 15.1 状态间的由此及彼 ✔️15.2 定时函数 文章目录 第 5 部分 添加动效 Adding motion第 15 章 过渡 Transitions15.1 状态间的由此及彼 From here…

【翻译】大型 Transformer 模型推理优化

翻译原文&#xff1a;Large Transformer Model Inference Optimization | LilLog 原文作者&#xff1a;Lilian Weng 目录 方法概述蒸馏 Distillation量化 Quantization Transformer 量化的挑战训练后量化 (PTQ) 混合精度量化 Mixed-precision quantization细粒度量化量化的二…

【Leecode】Leecode刷题之路第88天之合并两个有序数组

题目出处 88-合并两个有序数组-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 88-合并两个有序数组-官方解法 方法1&#xff1a;直接合并后排序 思路&#xff1a; 代码示例&#xff1a…

Java图片拼接

最近遇到一个挺离谱的功能&#xff0c;某个表单只让上传一张图&#xff0c;多图上传会使导出失败。跟开发沟通后表示&#xff0c;这个问题处理不了。我... 遂自己思考&#xff0c;能否以曲线救国的方式拯救一下&#xff0c;即不伤及代码之根本&#xff0c;又能解决燃眉之急。灵…

bridge between Lua world and the .NET

一、新建项目&#xff1a;luademo 安装包&#xff1a;<PackageReference Include"NLua" Version"1.7.3" /> using NLua; using System;namespace luademo {internal class Program{static void Main(string[] args){Lua state new Lua();for (int …

跟着问题学23番外——反向传播算法理论(1)

前向传播与反向传播 在单层神经网络的优化算法里&#xff0c;我们讲到优化算法是为了寻找模型参数使得网络的损失值最小&#xff0c;这里详细介绍一下应用的基础——反向传播算法。 在神经网络中&#xff0c;梯度计算是通过反向传播算法来实现的。反向传播算法用于计算损失函…

Liveweb视频融合共享平台在果园农场等项目中的视频监控系统搭建方案

一、背景介绍 在我国的大江南北遍布着各种各样的果园&#xff0c;针对这些地处偏僻的果园及农场等环境&#xff0c;较为传统的安全防范方式是建立围墙&#xff0c;但是仅靠围墙仍然无法阻挡不法分子的有意入侵和破坏&#xff0c;因此为了及时发现和处理一些难以察觉的问题&…

华为IPD流程6大阶段370个流程活动详解_第二阶段:计划阶段 — 86个活动

华为IPD流程涵盖了产品从概念到上市的完整过程,各阶段活动明确且相互衔接。在概念启动阶段,产品经理和项目经理分析可行性,PAC评审后成立PDT。概念阶段则包括产品描述、市场定位、投资期望等内容的确定,同时组建PDT核心组并准备项目环境。团队培训涵盖团队建设、流程、业务…

开源轮子 - EasyExcel01(核心api)

EasyExcel01 - 核心api 本文整理自掘金大佬 - 竹子爱熊猫 https://juejin.cn/post/7405158045662576640 文章目录 EasyExcel01 - 核心api一&#xff1a;初相识EasyExcel1&#xff1a;写入excel入门2&#xff1a;读取Excel入门 二&#xff1a;数据模型注解1&#xff1a;读写通用…

实验13 C语言连接和操作MySQL数据库

一、安装MySQL 1、使用包管理器安装MySQL sudo apt update sudo apt install mysql-server2、启动MySQL服务&#xff1a; sudo systemctl start mysql3、检查MySQL服务状态&#xff1a; sudo systemctl status mysql二、安装MySQL开发库 sudo apt-get install libmysqlcli…

【java基础系列】实现数字的首位交换算法

在java中&#xff0c;手写实现一个数字的首位交换算法实现 实现效果 实现代码 核心业务代码 public static void main(String[] args) {int[] arr {1,2,3,4,5};int temp arr[0];for (int i 0; i < arr.length; i) {System.out.print(arr[i]);}System.out.println(&quo…

kubeadm一键部署K8S 集群架构

kubeadm一键部署K8S 集群架构(centos7) https://www.k8src.cn/ https://kubernetes.io/zh-cn/docs/home/ https://blog.csdn.net/m0_58709145/article/details/140128179 https://blog.csdn.net/jiaqijiaqi666/article/details/129745828 Kubeadm init报错[ERROR CRI]: contai…

【LeetCode: 876. 链表的中间结点 + 链表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Linux下基于最新稳定版ESP-IDF5.3.2开发esp32s3入门hello world输出【入门一】

开发环境搭建&#xff1a;Linux-Ubuntu下搭建ESP32的开发环境的步骤&#xff0c;使用乐鑫最新稳定版的esp-idf-CSDN博客 一、安装好开发环境后&#xff0c;在esp目录下再创建一个esp32的目录【用于编程测试demo】 二、进入esp32目录&#xff0c;打开终端【拷贝esp-idf的hello工…

单节点calico性能优化

在单节点上部署calicov3273后&#xff0c;发现资源占用 修改calico以下配置是资源消耗降低 1、因为是单节点&#xff0c;没有跨节点pod网段组网需要&#xff0c;禁用overlay方式网络(ipip&#xff0c;vxlan),使用route方式网络 配置calico-node的环境变量 CALICO_IPV4POOL_I…

基于鲲鹏服务器的打砖块小游戏部署

案例介绍 鲲鹏服务器是基于鲲鹏处理器的新一代数据中心服务器&#xff0c;适用于大数据、分布式存储、高性能计算和数据库等应用。鲲鹏服务器具有高性能、低功耗、灵活的扩展能力&#xff0c;适合大数据分析、软件定义存储、Web等应用场景。 本案例将指导开发者如何在鲲鹏服务…