LeetCode 3. Longest Substring Without Repeating Characters

LeetCode 3. Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters.

Examples:

Given “abcabcbb”, the answer is “abc”, which the length is 3.

Given “bbbbb”, the answer is “b”, with the length of 1.

Given “pwwkew”, the answer is “wke”, with the length of 3. Note that the answer must be a substring, “pwke” is a subsequence and not a substring.

题目即要求找到一个字符串中不含重复字符的最长子串。子串(substring)必须是连续的,子序列(subsequence)才可以是不连续的。

暴力解法当然是以每一个字符为起始位置,往后直到遇到重复字符为止。这样时间复杂度为O(n^2)的解法显然是不能通过的。

假设使用length[i]来表示以第i个字符s[i]结束的不重复子串的长度。考虑length[i]与length[i-1]的关系:
- 如果s[i]也没有出现在以s[i-1]结束的子串中,那么显然,length[i] = lengh[i-1] + 1。
- 如果s[i]是一个重复的字符,那么有,length[i] = i - k,其中k为前一个与s[i]相同的字符的下标。

如果我们仍然通过遍历来找到k值的话,就完全没有优化这个问题了。因此,可以使用last_position[ch]来表示字符ch上一次出现的位置,那么状态转移方程就可以表示为:

IF s[i] exists
    length[i] = i - last_position[s[i]];
ELSE
    length[i] = length[i - 1] + 1;

同时,利用last_position也便于判断s[i]是否是重复字符:当满足last_position.at(s[i]) >= i - 1 - length[i - 1],即s[i]最后一次出现的位置已经在以s[i-1]结尾的子串中,那么如果加入s[i],显然就会出现重复字符了。

利用以上动态规划的思想,将时间复杂度降低到了O(n)。

代码实现如下:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int max_length = s.length();
        if (max_length == 0) {
            return 0;
        }

        vector<int> length(max_length, 0);
        map<char, int> last_position;
        int answer = 1;
        length[0] = 1;
        last_position[s[0]] = 0;

        for (int i = 1; i < max_length; i++) {
            if (last_position.find(s[i]) != last_position.end() && last_position.at(s[i]) >= i - 1 - length[i - 1]) {
                length[i] = i - last_position[s[i]];
            }
            else {
                length[i] = length[i - 1] + 1;
            }
            last_position[s[i]] = i;

            if (length[i] > answer) {
                answer = length[i];
            }
        }
        return answer;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值