LeetCode | Longest Substring Without Repeating Characters(最长连续不重复子串)


题目:

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.

找出最长不重复的连续子串。


题目解析:

题意很简单,就是要找到最长的连续的子串。


思路一:

最先考虑到的就是求第i位字符开头的,最大的子串长度。没增加第j位的字符,就要与i -- j-1之间的字符相比较,直到出现重复或者遍历完为止。这也是最复杂的,需要O(n^2)时间复杂度。中间要设置一个maxlen变量,判断第i位开始的字符是否超过了最大长度。


思路二:

我们可以从《最大连续子数组和》得到启发,我们求第i位字符结尾的最大长度:遍历到第i位的时候,如果和前面不重复,就max++(这里为max不是maxlen);如果重复,通过遍历从i-maxlen到i-1位的字符,与第i位字符相比较,找到相等的位j,那么maxlen可能会被i-j更新!

然后再遍历i+1位的字符。。。

这个思路比上面的有一点改进,不过也是需要比较后才能得到,时间复杂度也有一点高。


思路三:

通常我们要降低时间复杂度,可以考虑牺牲空间来获得。

我们通过hash表,并附设两个“指针”i和j;用字符的整数值当索引,值为0或1表示是否之前存在。当存在了,就将i++并清零,直到j所表示的字符被清零为止。

比如abcdba,当j等于4的时候,arr[1]是为1的,此时i为0,那么先将arr[0]和arr[1]清零,然后再对arr[1]赋值为1。

int LengthOfLongestSubstring(char *str)
{
    int i,j;
    int maxlen = 0; //要初始化,不然产生意外结果!
    int n = strlen(str);
    int arr[256] = {0};     //设置hash表,索引为字符的值,值为是否存在该字符!

    for(i = 0,j = 0;j < n;j++){
        while(arr[str[j]] == 1){
            arr[str[i]] = 0;
            ++i;
        }
        arr[str[j]] = 1;
        maxlen = maxlen > (j-i) ? maxlen : j-i+1;
    }

    return maxlen;
}


思路四:

通常我们能想到用哈希表,但是往往在索引和值表示的概念上造成混乱。一般索引用要判断字符是否存在的字符值来表示,而值就是我们关心的是否存在,这就得出了思路三。但进一步想想,我们知道了他存在,但还想知道具体位置。

方案一:我们可以再另外附设一个数组,来表示其存储的位置

用一个start和end来记录目前考察的字符串的开头和结尾
用exist[26]来记录目前字符串中出现过的字母
用position[26]来记录出现过的字符串的字母的位置

然后我们往后走一位,然后和exist来比较看这个字母是否已经出现过了。

1 如果出现过了,那么我们把start移动到之前那个字母出现的位置的后一位,end往后移动一位
2 如果没有出现过,那么我们就把end往后移动一位

代码:

int lengthOfLongestSubstring(string s) 
{
    int max = 0, start = 0;
    bool exist[26];
    int position[26];
    
    for(int i = 0; i < 26; i++) {
        exist[i] = false;
        position[i] = 0;
    }
    
    for(int i = 0; i < s.size(); i++) {
        if(exist[s[i] - 'a']) {
            for(int j = start; j <= position[s[i] - 'a']; j++) {
                exist[s[j] - 'a'] = false;
            }
            start = position[s[i] - 'a'] + 1;
            exist[s[i] - 'a'] = true;
            position[s[i] - 'a'] = i;
        }
        else {
            exist[s[i] - 'a'] = true;
            position[s[i] - 'a'] = i;
            max = max > (i - start + 1) ? max : (i - start + 1);
        }
    }

    return max;
}


方案二:

-----错误的做法!!!比如abbbbbba应该输出2,但是按照这个的话,会输出7。

我们不仅要保存位置,还要取 len = min(len+1,j-index); if(len > max) max = len。之所以要取最小值,是因为len的长度要么大幅度减小,要么一个一个增加,而j-index可能很大。


我们完全可以让思路三中的arr[]数组存储位置即可!当存在了,就更新其为最新的位置即可。当已经存在了,就将j-index与最大长度相比,看是否更新,并将索引数组更新为j。

代码如下:

int LengthOfLongestSubstring1(char *str)
{
    int idex = -1,j;
    int maxlen = 0; //要初始化,不然产生意外结果!
    int n = strlen(str);
    int arr[256];     //设置hash表,索引为字符的值,值为是否存在该字符!

    memset(arr,-1,256 * sizeof(int));   //设置的是字节数,因此要乘以sizeof(int)
    for(j = 0;j < n;j++){
        if(arr[str[j]] > -1){
            idex = arr[str[j]];
        }
        arr[str[j]] = j;
        if(j-idex > maxlen)
            maxlen = j-idex;
    }

    return maxlen;
}


正确代码:

class Solution {
public:
    int lengthOfLongestSubstring(string s){
        int idex = -1,j;
        int maxlen = 0,len = 0; //要初始化,不然产生意外结果!
        int n = s.size();
        if(n == 0)
            return 0;
        int arr[256];     //设置hash表,索引为字符的值,值为是否存在该字符!
    
        memset(arr,-1,256 * sizeof(int));   //设置的是字节数,因此要乘以sizeof(int)
        for(j = 0;j < n;j++){
            idex = arr[s[j]];
            arr[s[j]] = j;
            len = len+1 > j-idex ? j-idex : len+1;
            if(len > maxlen)
                maxlen = len;
        }

        return maxlen;
    }
};



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,有三种方法可以解决LeetCode上的最长回文子串问题。 方法一是使用扩展中心法优化,即从左向右遍历字符串,找到连续相同字符组成的子串作为扩展中心,然后从该中心向左右扩展,找到最长的回文子串。这个方法的时间复杂度为O(n²)。\[1\] 方法二是直接循环字符串,判断子串是否是回文子串,然后得到最长回文子串。这个方法的时间复杂度为O(n³),效率较低。\[2\] 方法三是双层for循环遍历所有子串可能,然后再对比是否反向和正向是一样的。这个方法的时间复杂度也为O(n³),效率较低。\[3\] 综上所述,方法一是解决LeetCode最长回文子串问题的最优解法。 #### 引用[.reference_title] - *1* [LeetCode_5_最长回文子串](https://blog.csdn.net/qq_38975553/article/details/109222153)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Leetcode-最长回文子串](https://blog.csdn.net/duffon_ze/article/details/86691293)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [LeetCode 第5题:最长回文子串(Python3解法)](https://blog.csdn.net/weixin_43490422/article/details/126479629)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值