【JZ-48】最长不含重复字符的子字符串(动态规划、滑动窗口)

题目

在这里插入图片描述

算法思路

f ( j ) f(j) f(j) 代表以字符 s [ j ] s[j] s[j] 作为结尾的【最长不含重复字符的子字符串】的长度,字符 s [ j ] s[j] s[j] 左边距离最近的相同字符为 s [ i ] s[i] s[i],则转移方程为:

  1. i < 0时,说明字符 s [ j ] s[j] s[j] 左边没有相同字符,则 f ( j ) = f ( j − 1 ) + 1 f(j)=f(j-1)+1 f(j)=f(j1)+1
  2. f(j-1) < j - i时,说明字符 s [ i ] s[i] s[i] 在子字符串 f ( j − 1 ) f(j-1) f(j1)的区间之外,则 f ( j ) = f ( j − 1 ) + 1 f(j)=f(j-1)+1 f(j)=f(j1)+1
  3. f(j-1) >= j - i时,说明字符 s [ i ] s[i] s[i] 在子字符串 f ( j − 1 ) f(j-1) f(j1)的区间之内,则 f ( j ) = j − i f(j)=j-i f(j)=ji
    其中情况1和情况2可以合并
    返回值:所有 f ( j ) f(j) f(j) 中的最大值
    问题的关键在于,对于每一个 s [ j ] s[j] s[j] 如何找到对应的索引 i i i

方法一-动态规划+哈希表

遍历字符串时,利用哈希表来记录各个字符最后一次出现的位置,这样遍历到 s [ j ] s[j] s[j] 时就可以通过访问哈希表 d i c [ s [ j ] ] dic[s[j]] dic[s[j]]来获取对应的索引 i i i

具体代码:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> dic = new HashMap<>();
        int res = 0, tmp = 0;
        for(int j = 0; j < s.length(); j++){
            int i = dic.getOrDefault(s.charAt(j), -1);//获取对应的索引i
            dic.put(s.charAt(j), j);//更新哈希表
            tmp = tmp < j - i ? tmp + 1 : j - i;//转移方程
            res = Math.max(res, tmp);//更新最大值
        }
        return res;
    }
}

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n),n 为字符串长度
  • 空间复杂度: O ( 1 ) O(1) O(1),字符的 ASCII 码范围为 0 ~ 127,故哈希表最多占用 O ( 128 ) = O ( 1 ) O(128)=O(1) O(128)=O(1) 的额外空间。

方法二-动态规划+线性查找

即不使用哈希表,通过从当前位置向前查找来获取对应的索引 i i i

具体代码:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        // Map<Character, Integer> dic = new HashMap<>();
        int res = 0, tmp = 0;
        for(int j = 0; j < s.length(); j++){
            //获取对应的索引i
            int i = j - 1;
            while(i >= 0 && s.charAt(i) != s.charAt(j))i--;
            // dic.put(s.charAt(j), j);//更新哈希表
            tmp = tmp < j - i ? tmp + 1 : j - i;//转移方程
            res = Math.max(res, tmp);//更新最大值
        }
        return res;
    }
}

复杂度分析:

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2),n 为字符串长度
  • 空间复杂度: O ( 1 ) O(1) O(1)

方法三-双指针+哈希表(滑动窗口)

具体代码:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> dic = new HashMap<>();
        int res = 0, i = -1;
        for(int j = 0; j < s.length(); j++){
            //获取对应的索引i
            if(dic.containsKey(s.charAt(j))){
                i = Math.max(i, dic.get(s.charAt(j)));//更新左边界索引i
            }
            dic.put(s.charAt(j), j);//更新哈希表
            res = Math.max(res, j - i);//更新结果
        }
        return res;
    }
}

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n),n 为字符串长度
  • 空间复杂度: O ( 1 ) O(1) O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值