最长不含重复字符的子字符串(剑指 Offer 48)

最长不含重复字符的子字符串(剑指 Offer 48)

1 问题描述

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

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

2 解题思路

长度为N的字符串共有(n+1)n/2个子字符串遍历复杂度为O(n²),判断长度为 N 的字符串是否有重复字符的复杂度为 O(N) ,因此本题使用暴力法解决的复杂度为O(n³)。

第一次想到使用HashSet降低,判断长度为 N 的字符串是否有重复字符的复杂度为O(1),向set中添加,返回false则有重复。因此使用双循环加HashSet的方式解题时间复杂度为O(n²)。

思想:第一层循环遍历字符串,从s[i](起始为0)开始,第二层循环送s[i+1]开始向set中添加元素,若返回flase,记录当前set大小即为本次不重复子串长度,并清空set退出第二层循环,用sum保存set大小的最大值。进入下一次循环从i+1开始判断。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.equals("")||s==null){
            return 0;
        }
        int sum=0;
        Set<Character> set = new HashSet<>();
        for(int i = 0;i<s.length();i++){
            set.add(s.charAt(i));
            for(int j = i+1;j<s.length();j++){
                if(!set.add(s.charAt(j))){
                    sum=Math.max(sum,set.size());
                    set.clear();
                    break;
                }
            }
            sum=Math.max(sum,set.size());
        }
        return sum;
    }
}

3 改进

使用暴力法时间复杂度太大,因此可以考虑使用动态规划降低时间复杂度。该问题主要就是要找到两个相隔最远的相同字符之间的距离,可以考虑使用HashMap保存每个字符的下标,遍历到相同字符时保存二者之间的距离并更新HashMap,最后返回每次保存的距离之间的最大值。

状态定义: 设动态规划列表 dpdp[j] 代表以字符 s[j] 为结尾的 “最长不重复子字符串” 的长度。

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

i<0 ,即s[j] 左边无与其相同字符,则 dp[j] = dp[j-1] + 1
dp[j−1]<j−i ,说明上一个与 s[i]相同的字符不在本次包含 s[i]的子字符串 dp[j-1]中,则 dp[j] = dp[j - 1] + 1
dp[j−1]≥j−i ,说明上一个与s[i] 想相同的字符在本次包含 s[i]的子字符串dp[j−1] 区间之中 ,则dp[j] 的左边界由 s[i] 决定,即 dp[j] = j - i

最后返回max(dp)

由于返回值是取 dp列表最大值,因此可借助变量 tmp 存储 dp[j] ,变量 res每轮更新最大值即可。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.equals("")||s==null){
            return 0;
        }
        int temp = 0;
        int res = 0;
        HashMap<Character,Integer> map = new HashMap<>();
        for(int i = 0;i<s.length();i++){
            int j = map.getOrDefault(s.charAt(i),-1);
            map.put(s.charAt(i),i);
            if(temp<i-j){
                temp++;
            }else{
                temp = i-j;
            }
            res = Math.max(res,temp);
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值