3. 无重复字符的最长子串

本文深入探讨了求解最长无重复子串问题的两种高效算法:动态规划与双指针法。通过实例分析,详细解释了每种方法的实现思路、关键步骤及代码实现。动态规划利用状态转移方程优化计算过程,而双指针法则通过移动两个指针快速定位最长无重复子串。文章还对比了两种方法的时间和空间复杂度。

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

题目分析

方法一:动态规划
求数组的连续字串相关,第一反应应该是动态规划,其中状态d[i]表示以第i个字符为结尾,无重复字符串的最长字串,状态转移方程:
d[i] = (s[i]是否与d[i-1]中的字符重复?找到重复的位置,d[i]等于两者相减:d[i-1]+1)
问题一:如何判断是否重复?
使用map或set
问题二:如何找到重复的位置?
使用map,其key = 字符,其value=位置。
问题三:需要每个d[i]都配一个map吗?
并不需要,一次遍历,判断d[i-1]的长度时候落在了当前重复字的区间内.
,如果出现新的重复,将其更新即可。

时间复杂度为O(n),空间复杂度为O(n)

方法二:双指针
使用两根起始位置在字符串头的指针i,p2。i先移动,当遇到重复的字母时,开始记录len1 = i-重复处的位置,len2=i-p,用max和len2比较,如果len1>=len2,就另p移动到重复处+1的地方,否则不改变p1的位置。
注意,最后要比较一下最后一个不重复的字符串和当前Max的值。

思考

双指针也比较适和求连续的字串这种问题,但是双指针的初始位置和移动路径应该如何安排,这个一定要想清楚。

代码

第一种方法:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int[] d = new int[s.length()+1];
        d[0] = 0;
        int len = s.length()+1;
        //d[i]初始化为1
        for(int i = 1;i<len;i++){
            d[i] = 1;
        }

        Map<Character,Integer> map = new HashMap<>();
        for(int i = 1;i<len;i++){
            char cur = s.charAt(i-1);
            if(map.containsKey(cur)){
                int tmpLen = i-map.get(cur)-1;
                if(tmpLen>d[i-1]){
                    d[i] = d[i-1]+1;
                }
                else{
                    d[i] = tmpLen;
                }
            }
            else{
                d[i] = d[i-1]+1;
            }
            map.put(cur,i-1);
        }

        int maxLen = 0;
        for(int i = 0;i<len;i++){
            maxLen=Math.max(d[i],maxLen);
        }
        return maxLen;
    }
}

第二种方法:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int p1 = 0;
        int p2 = 0;
        int max = 0;
        Map<Character,Integer> map = new HashMap<>();
        for(int i = 0;i<s.length();i++){
            char cur = s.charAt(i);
            if(map.containsKey(cur)){
                int len1 = i-p1;
                int len2 = i-map.get(cur);
                max = Math.max(max,len1);
                if(len2<=len1){
                    p1=map.get(cur)+1;
                }
            }
            map.put(cur,i);
        }
        max = Math.max(s.length()-p1,max);
        return max;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值