【LeetCode刷题(中等程度)】剑指 Offer 48. 最长不含重复字符的子字符串

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

示例 1:

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

输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:

输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路1:利用滑动窗口,这个窗口中对应的字符是没有重复的。首先我们需要两个指针来指示左右边界。start表示左边界,end表示右边界,用一个哈希表存储我们遍历过的字符的,以此来指示是否遍历到了一个重复的字符。

注意我们遍历的时候,有可能这个重复字符会出现在当前左边界start的左边,那么我们没必要把start往回退,因为这肯定不符合题意的。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char,int> table;
        int ans = 0;
        for(int end = 0,start = 0;end<s.size();++end)
        {
            char alpha = s[end];//判断当前字符是什么
            if(table.find(alpha) != table.end())//表示有重复
                start = max(table[alpha],start);//保证不回溯
            ans = max(ans,end - start + 1);//ans已经保留了以前找到的最长子串的值
            table[alpha] = end + 1;//否则就将当前字符的下一位置加入
        }
        return ans;
    }
};

思路二:动态规划

我们用f[i]来表示到索引为i这个位置的最长不重复子串的长度。
初始条件:f[0] = 1,即到索引为0这个字符的最长不重复子串的长度为1

我们需要用一个哈希表来存储遍历过的不重复字符的索引下标。
那么转移方程:
若当前字符并未出现过则:f[i] = f[i -1] + 1
若当前字符已经出现过,并且和上次出现这个字符的位置之差小于等于f[i - 1],例如字符串arabcacfr,字符a距离上次出现的距离d2,而f[1] = 2,那么到这个a的最长不重复子串就是d,即f[i] = d
若当前字符已经出现过,并且和上次出现这个字符的位置之差大于f[i - 1],例如字符串arabcacfr,字符r距离上次出现的距离d7,而f[7] = 3,那么到这个r的最长不重复子串,仍然是f[i] = f[i - 1] +1,因为我们不能回溯超过f[i - 1]长度的位置,毕竟位置之差大于f[i - 1]已经证明重复的字符一定在前面的子串中,而不是发生在已经得到的最长不含重复字符的子串中。所以此时的f[i] = f[i - 1] + 1

代码:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.size();
        if(n == 0)
            return 0;
        unordered_map<char,int> table;
        vector<int>f(n,0);
        f[0] = 1;
        table[s[0]] = 0;
        for(int i = 1;i < n;++i)
        {
            char alpha = s[i];//判断当前字符是什么
            if(table.find(alpha) != table.end())//表示有重复
            {
                int d = i - table[alpha];
                if(d <= f[i - 1])
                {
                    f[i] = d;
                }
                else
                {
                    f[i] = f[i - 1] + 1;
                }
                table[alpha] = i;//这里要更新重复字符比较新的位置
            }
            else
            {
                f[i] = f[i - 1] + 1;
                table[alpha] = i;
            }
        }
        return *max_element(f.begin(),f.end());
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值