[LeetCode] Longest Substring Without Repeating Characters

本文详细介绍了如何使用哈希表和动态更新机制解决字符串中最长无重复子串问题,提供了两种解决方案,一种为O(n^2)复杂度,另一种为优化后的O(n)复杂度。通过实例解释了算法的核心思想和实现细节。

Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.

  这道题经过了一番苦苦挣扎还是没能解出来。虽然借助哈希表可以弄到O(n^2)但是题目要求是O(n),感觉有用点DP的技巧,其实基本思想就是当遇到重复的时候,不用从下一个字符开始搜索。举个栗子:

abcdefdh

  高亮的是目前处理到的最长不重复子串,现在处理到d的时候,发现了重复,此时我们没有必要从b 开始重新搜索,而是算出两个d 之间有多少字符,这些字符可以组成新的不重复子串参与到下一次搜索中,这里我们有ef 两个字符,加上新来的d,就是3个字符,这个很好算:通过两个d 的id相减就可以了(6-3=3)

这里我遇到的问题是,怎么在新的一轮搜索中更新hash表的内容,因为新的最长不重复子串是efd,前面的abcd就应该从hash表中移除。但是移除操作本身是O(n)的,没法做到O(1)。。。于是就陷进去了。

  最后看了答案,发现思路是很相似的,怎么解决我上面遇到的问题呢?就是维护“最后出现位置”的机制,这样我们就不用去纠结怎么把hash表里的东西删掉了,只用每次都更新hash表里对应字符的id。接着上面的栗子说:

当遇到第二个d 的时候,我们不仅检查d 是否在hash表中,而且还要检查当前index(6)减去目前最长不重复子串长度(3)是否小于等于d 在hash 表中对应的id(3) 这里:6-3 <= 3 就说明上一个d确实包含在当前的最长不重复子串中。

 

说的有点糊涂。。直接看代码可能还清晰点:

int lengthOfLongestSubstring(string s) {
    int n = (int)s.size();
    if (!n) return 0;
    int len = 0, max = 0;
    unordered_map<char, int> map;
    
    for (int i = 0; i < n; i++) {
        if (map.find(s[i]) == map.end() || map[s[i]] < i - len) {
            len++;
        }
        else {
            if (len > max) { max = len; }
            len = i - map[s[i]];
        }
        map[s[i]] = i;
    }
    return len > max ? len : max;
}

 

O(n^2)的解法:

int lengthOfLongestSubstring(string s) {
    if (!s.size()) return 0;
    int len = 0;
    int max = 0;
    unordered_map<char, int>set;
    
    for (int i = 0; i < s.size(); i++) {
        if (s.size()-i-1 < max) break;
        for (int j = i; j < s.size(); j++) {
            if (set.find(s[j]) == set.end()) {
                len++;
                set[s[j]] = j;
            }
            else {
                i = set[s[j]];
                break;
            }
        }
        if (len > max) {
            max = len;
        }
        set.clear();
        len = 0;
    }
    
    return max;
}
O(n^2)

 

转载于:https://www.cnblogs.com/agentgamer/p/4116432.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值