无重复字符的最长子串|刷题打卡

529 阅读3分钟

本文正在参与掘金团队号上线活动,点击 查看大厂春招职位

题目描述:

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

思路分析

首先说一下什么是子串和子序列。
子序列指字符串中不连续的子字符串。
子串指字符串中连续的子字符串。
例如:字符串:123456789; 子序列:13579(非连续),子串:12345(连续)。

回到题目,找出不含有重复字符的最长子串的长度。
例如:字符串"abcabcbb",无重复字符的最长子串是 "abc",所以其长度为 3。
字符串"pwwkew",无重复字符的最长子串是 "wke"或"kew",所以其长度为 3。如果带上p,"pwke"这就是子序列。

实现方法上,可以去遍历字符串,charAt方法拿到每一个字符,用一个变量去存储不重复的子串,同时通过indexOf去判断是否存储过遍历的字符。

代码 Talk is cheap,show you the code

遍历字符串,s.charAt(i)取出每一个字符,str.indexOf(char) 判断当前字符是否已经存在,如果不存在,添加该字符,如果存在,str.substr(index + 1) + char 截取该字符之后的字符串,再加上新的字符,拼凑成新的子串。

const lengthOfLongestSubstring = function (s) {
    let result = 0; // 最长子串的长度
    let str = ""; // 存放无重复子串
    for (let i = 0; i < s.length; i++) {
        let char = s.charAt(i);
        //判断当前字符是否已经存在
        let index = str.indexOf(char);
        if (index === -1) {
            //字符不存在,添加该字符
            str += char;
            result = result < str.length ? str.length : result;
        } else {
            //字符已存在,截取存在字符之后的字符串,再加上新的字符,组成新的子串
            str = str.substr(index + 1) + char;
        }
    }
    return result;
};

举个例子 s="pwwkew"

i=0,str="p"result=1
i=1,str="pw"result=2
i=2,此时char="w"str="pw"里包含w字符,位于index=1的位置,str截取,重新赋值后为w,str="w",result=2大于当前str长度,仍为2
i=3,str="wk"result=2
i=4,str="wke"result=3
i=5,此时char="w"str="wke"里包含w字符,位于index=0的位置,str截取,重新赋值后为str="kew"result=3

返回值result就是字符的长度。

除了上面的方法,还可以通过滑动窗口的方式来实现,使用两个指针表示字符串中某个子串的左右边界,在每一步的操作中,将左指针向右移动一格,右指针不断地向右移动,保证这两个指针对应的子串中没有重复的字符,枚举结束后,找到最长的子串, 更多详细内容可以参考Leetcode官方的讲解

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

总结

一开始写无从下手,后面慢慢分析,一行行写,加打印,逐渐排查得出方法。