(动态规划) 剑指 Offer 48. 最长不含重复字符的子字符串 ——【Leetcode每日一题】

news/2024/6/16 8:21:38 标签: 动态规划, leetcode, 算法

❓剑指 Offer 48. 最长不含重复字符的子字符串

难度:中等

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

示例 1:

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

示例 2:

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

示例 3:

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

提示

  • s.length <= 40000

注意:本题与 3. 无重复字符的最长子串 相同。

💡思路:动态规划

定义 dp 数组,dp[i] 代表以字符 s[i] 为结尾的 “最长不重复子字符串” 的长度。

固定右边界 i ,设字符 s[i] 左边距离最近的相同字符为 s[j] ,即 s[j] = s[i]

  • i < 0 ,即 s[i] 左边无相同字符,则 dp[i] = dp[i−1] + 1
  • dp[i−1] < i - j,说明字符 s[i] 在子字符串 dp[i−1] 区间之外 ,则 dp[i] = dp[i−1] + 1
  • dp[i−1] ≥ i - j ,说明字符 s[j] 在子字符串 dp[i−1] 区间之中 ,则 dp[i] 的左边界由 s[j] 决定,即 dp[i] = i − j

所以 状态转移方程 为:
d p [ i ] = { d p [ i − 1 ] + 1 , i < 0 d p [ i − 1 ] + 1 , d p [ i − 1 ] < i − j i − j , d p [ i − 1 ] ≥ i − j dp[i]=\begin{cases}dp[i-1]+1&,i<0\\dp[i-1]+1&,dp[i-1]<i-j\\i-j&,dp[i-1]\geq i-j\end{cases} dp[i]= dp[i1]+1dp[i1]+1ij,i<0,dp[i1]<ij,dp[i1]ij

观察发现 dp[i] 只与 dp[i - 1] 有关,所以只需定义一个变量 curLen 记录上一个长度。

使用哈希表统计:

  • 遍历字符串 s 时,使用哈希表(记为 preIndexs )统计 各字符最后一次出现的索引位置
  • 遍历到 s[i] 时,可通过访问哈希表 preIndexs[s[i]] 获取最近上一个的相同字符的索引 pre

🍁代码:(C++、Java)

C++

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int curLen = 0;
        int maxLen = 0;
        map<char, int> preIndexs;
        for(int i = 0; i < s.size(); i++){
            int pre = preIndexs.find(s[i]) == preIndexs.end() ? -1 : preIndexs[s[i]]; // 获取当前字符的索引
            curLen = curLen < i - pre ? curLen + 1 : i - pre; // dp[i - 1] -> dp[i]
            maxLen = max(maxLen, curLen);
            preIndexs[s[i]] = i;
        }
        return maxLen;
    }
};

Java

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int curLen = 0;
        int maxLen = 0;
        Map<Character, Integer> preIndexs = new HashMap<>();
        for(int i = 0; i < s.length(); i++){
            int pre = preIndexs.getOrDefault(s.charAt(i), -1); // 获取当前字符的索引
            curLen = curLen < i - pre ? curLen + 1 : i - pre; // dp[i - 1] -> dp[i]
            maxLen = Math.max(maxLen, curLen);
            preIndexs.put(s.charAt(i), i);
        }
        return maxLen;
    }
}

🚀 运行结果:

在这里插入图片描述

🕔 复杂度分析:

  • 时间复杂度 O ( n ) O(n) O(n),其中 n 为字符串 s 的长度。
  • 空间复杂度 O ( 1 ) O(1) O(1),字符的 ASCII 码范围为 0 ~ 127 ,哈希表 preIndexs 最多使用 O ( 128 ) = O ( 1 ) O(128)=O(1) O(128)=O(1) 大小的额外空间。

题目来源:力扣。

放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我LeetCode主页 / CSDN—力扣专栏,每日更新!

注: 如有不足,欢迎指正!


http://www.niftyadmin.cn/n/4974642.html

相关文章

C# 学习笔记--个人学习使用 <1>

C# 学习笔记 Chapter 1 C# 比较软的基础部分Section 1 类与命名空间Part 1 命名空间 NameSpacePart 2 类 Class Section 2 基本元素Section 3 数据类型Part 1 什么是类型&#xff1f;Part 2 类型在 C Sharp 中的作用Part 3 C Sharp 中的数据类型 Section 4 变量、对象与内存Par…

msvcp140.dll丢失的解决方法,win10系统dll报错的解决方法

今天&#xff0c;我将为大家分享一个关于msvcp140.dll丢失的解决方法&#xff0c;特别是针对在Windows 10系统上遇到这个问题的朋友们。在开始之前&#xff0c;我想先简要介绍一下msvcp140.dll文件的作用。msvcp140.dll是Microsoft Visual C运行时库的一部分&#xff0c;它包含…

Linux Day10 ---Mybash

目录 一、Mybash介绍 1.1.mybash.c 打印函数 分割函数 命令函数 二、Mybash实现 2.1.打印函数 2.1.1需要使用到的功能函数 1.获取与当前用户关联的UID 2.获取与当前用户的相关信息---一个结构体&#xff08;passwd&#xff09; 3.获取主机信息 4.获取当前所处位置 5.给…

QT使用QXlsx实现数据验证与Excel公式操作 QT基础入门【Excel的操作】

准备环境:QT中使用QtXlsx库的三种方法 1、公式操作写单行公式 //右值初始化Format rAlign;rAlign.setHorizontalAlignment(Format::AlignRight);//左值初始化Format lAlign;lAlign.setHorizontalAlignment(Format::AlignLeft);xlsx.write("B3", 40, lAlign);xlsx.wr…

小研究 - Java虚拟机即时编译器的一种实现原理

深入分析了 &#xff2b;&#xff41;&#xff46;&#xff46;&#xff45;虚拟机的 &#xff2a;&#xff29;&#xff34;&#xff08;&#xff2a;&#xff55;&#xff53;&#xff54;&#xff0d;&#xff29;&#xff4e;&#xff0d;&#xff34;&#xff49;&#xf…

常见的可以提升编码效率的 modern C++ 语法糖【1】

文章目录 std::optionalstd::string_view的使用std::variant使用std::function 与 std::bind函数std::forward使用 std::optional std::optional 是 C17 中引入的一个模板类&#xff0c;它可以表示一个可能不存在的值。std::optional 的使用方法非常简单&#xff0c;它可以用于…

Java IO流动(实战操作)

目录 1 IO流原理2 IO流的分类3 输入、输出流代码示例4 小结5 文件在前后台之间传递 在Java中&#xff0c;IO流是一种用于处理输入和输出操作的机制。它提供了一种统一的方式来读取和写入数据&#xff0c;平日开发中在文件读写&#xff0c;网络通信&#xff0c;特定场景的数据库…

Python函数对象

python有以下几种可调用对象&#xff1a; 用户自定义函数Lambda表达式创建的匿名函数内置函数内置方法类方法类&#xff0c;主要是类的魔法方法&#xff0c;如构建函数、析构函数等函数对象&#xff0c;可调用类实例生成器 本文主要学习函数对象。 函数对象概念 在Python中…