闯关leetcode——3.Longest Substring Without Repeating Characters

大纲

题目

地址

https://leetcode.com/problems/longest-substring-without-repeating-characters/description/

内容

Given a string s, find the length of the longest substring without repeating characters.

Example 1:

Input: s = "abcabcbb"

Output: 3

Explanation: The answer is "abc", with the length of 3.

Example 2:

Input: s = "bbbbb"

Output: 1

Explanation: The answer is "b", with the length of 1.

Example 3:

Input: s = "pwwkew"

Output: 3

Explanation: The answer is "wke", with the length of 3.

Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.

Constraints:

  • 0 <= s.length <= 5 * 104
  • s consists of English letters, digits, symbols and spaces.

解题

这题是要在一个只包含English letters, digits, symbols and spaces 的字符串中找打最长不重复 子串。

一种比较容易想到的思路是:遇到重复的字符,则从上次这个字符出现的位置的后个位置开始尝试比较。比如abcdef是当前最长不重复子串。如果后面出现的字符是b,则从下标为1的b的后一位(c)开始组成新的测试子串,即cdefb。当新的测试子串的长度大于当前最长的子串,则更新该最大长度值。

为了判断后续出现的字符是否已经存在于当前最长子串中,则可以考虑使用map<char,int>的结构来存储最长子串及其坐标信息。但是这个题目存在只包含English letters, digits, symbols and spaces 的条件,这意味着每个字符都是ASCII码中的字符------它只有128个------且是连续的数字(见https://baike.baidu.com/item/ASCII/309296)。我们可以充分利用这个条件,使用一个更加紧凑高效的结构来存储这个关系。

cpp 复制代码
        array<int, 128> charIndex;
        charIndex.fill(-1);

然后我们遍历整个字符串,将这样的关系存储起来。

cpp 复制代码
for (int i = 0; i < s.size(); i++) {
......
	charIndex[int(s[i])] = i;
......
}

这儿有一个问题:在寻找过程中,如果最长子串发生了变化,则被剔除出的字符串是否应该从charIndex中剔除?比如上例abcdef是最长子串时,charIndex包含这些字符以及它们的位置。如果在f后面新出现的字符是b,则要开始新探索的子串是cdefb,这个时候字符a是否需要从charIndex中剔除?因为它可能会影响到后续再次出现a时的判断。实际我们通过新探索的子串开头第一个字符位置来判断新的重复是否需要处理。在这个例子中,第一个a(绿色)位于新子串cdefb起始位置(箭头处)的左侧,即使它存在charIndex中,也不会影响后续的探索,即我们可将新的探索子串定义为cdefba。假设下一个出现的是字符d,由于上一次出现的d位于子串起始位置(箭头处)的右侧,所以需要重新探索新的子串

经过分析,我们知道子串起始位置也是需要记录,以用于辅助判断是否要使用新子串。

由于该题只是要输出最长子串长度,并不要求输出最长子串的内容,所以我们并不用记录子串的具体顺序,只要比较并保留最长的一条串的长度即可。

最长串的比较maxLen = max(maxLen, i - start)可以优化到串的起始位置发生变化的时候进行。这样可以将对比的次数降到最低。

cpp 复制代码
#include <string>
#include <array>
using namespace std;

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        array<int, 128> charIndex;
        charIndex.fill(-1);
        int start = 0;
        int maxLen = 0;
        for (int i = 0; i < s.size(); i++) {
            if (charIndex[int(s[i])] >= start) {
                maxLen = max(maxLen, i - start);
                start = charIndex[int(s[i])] + 1;
            }
            charIndex[int(s[i])] = i;
        }

        if (s.size() - start > maxLen) {
            maxLen = s.size() - start;
        }
        
        return maxLen;
    }
};

上述代码的一个边界问题是:最长子串的尾部正好是原始串的尾部。这样我们必须在遍历结束后,考虑这种情况下最长子串的可能性。

代码地址

https://github.com/f304646673/leetcode/tree/main/3-Longest-Substring-Without-Repeating-Characters

相关推荐
C语言小火车2 分钟前
C++ 堆排序深度精讲:基于完全二叉树的选择排序进化,最坏情况 O(n log n) 的稳定王者
开发语言·c++·算法·排序算法·堆排序
kebidaixu10 分钟前
两轮BMS AFE SH367306 I2C 读写时序
算法
智能排队系统_头部供应商10 分钟前
RK3588边缘网关改造银行排队系统实战
算法
Fabarta30 分钟前
从 0 实现 ChatGPT 风格的流式对话 UI
算法·架构
手写码匠37 分钟前
手写 AI 上下文压缩系统:从零实现 Prompt 压缩与选择性上下文管理
人工智能·深度学习·算法·aigc
EAI-Robotics1 小时前
机器人操作鲁棒性:当机械手遇上真实世界的不确定性
人工智能·算法·机器人
Tairitsu_H2 小时前
[LC优选算法#17] 链表 | 合并 K 个升序链表 | K个⼀组翻转链表
数据结构·算法·链表
_olone2 小时前
Luogu P2704 [NOI2001] 炮兵阵地
c++·算法·状压dp
kebidaixu3 小时前
两轮BMS 防打火策略详解
算法
wabs6664 小时前
关于动态规划【力扣1035.不相交的线和53.最大子数组和的思考】
算法·leetcode·动态规划