高频刷题-3 Longest Substring Without Repeating Characters

本文介绍了如何解决LeetCode上的3号问题——找到字符串中最长的无重复字符子串。首先,讨论了暴力求解的高复杂度,接着提出了动态规划的优化方案,降低到O(n^2)。最后,详细解释了一种线性时间复杂度O(n)的解题方法,利用滑动窗口和HashSet实现。在该算法中,通过左右窗口的移动来保持无重复字符的子串,并确保每个元素只被访问一次,达到高效求解的目的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

这道题用的方法是在LeetCode中很常用的方法,对于字符串的题目非常有用。 首先brute force的时间复杂度是O(n^3), 对每个substring都看看是不是有重复的字符,找出其中最长的,复杂度非常高。优化一些的思路是稍微动态规划一下,每次定一个起点,然后从起点走到有重复字符位置,过程用一个HashSet维护当前字符集,认为是constant操作,这样算法要进行两层循环,复杂度是O(n^2)。 

public static int lengthOfLongestSubstring(String s) {

    int len = s.length();
    int subStringLen = 0;
    Set<Character> set = new HashSet<>();

    for (int i = 0; i < len; i++) {
        for (int j = i; j < len; j++) {
            if (!set.contains(s.charAt(j))) {
                set.add(s.charAt(j));
                subStringLen = Math.max(set.size(), subStringLen);
            } else {
                subStringLen = Math.max(set.size(), subStringLen);
                set.clear();
                break;
            }
        }
    }
    return subStringLen;
}

 

最后,我们介绍一种线性的算法,也是这类题目最常见的方法。基本思路是维护一个窗口,每次关注窗口中的字符串,在每次判断中,左窗口和右窗口选择其一向前移动。同样是维护一个HashSet, 正常情况下移动右窗口,如果没有出现重复则继续移动右窗口,如果发现重复字符,则说明当前窗口中的串已经不满足要求,继续移动有窗口不可能得到更好的结果,此时移动左窗口,直到不再有重复字符为止,中间跳过的这些串中不会有更好的结果,因为他们不是重复就是更短。因为左窗口和右窗口都只向前,所以两个窗口都对每个元素访问不超过一遍,因此时间复杂度为O(2*n)=O(n),是线性算法。空间复杂度为HashSet的size,也是O(n). 代码如下:

public int lengthOfLongestSubstring(String s) {
        /*
        基本思路是维护一个窗口,每次关注窗口中的字符串,在每次判断中,左窗口和右窗口选择其一向前移动。
        同样是维护一个HashSet, 正常情况下移动右窗口,如果没有出现重复则继续移动右窗口,如果发现重复字符,
        则说明当前窗口中的串已经不满足要求,继续移动有窗口不可能得到更好的结果,此时移动左窗口,直到不再有重复字符为止,
        中间跳过的这些串中不会有更好的结果,因为他们不是重复就是更短.
         */

        int len = s.length();
        int left = 0, right = 0, result = 0;
        Set<Character> set = new HashSet<Character>();

        while(right < len) {
            if (!set.contains(s.charAt(right))) {
                set.add(s.charAt(right++));
                result = Math.max(result, set.size());
            } else {
                set.remove(s.charAt(left++));
            }
        }
        return result;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值