无重复字符的最长子串

与世无争的帅哥 提交于 2020-02-21 05:26:04

这是一道十分经典的题目,但对与我这样一个入门级的小白来说,做出来并理解它也花了不少的功夫啊。
题目:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
例:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
这道题我第一次见是在我们学校的一次考试上,当时只能想到暴力法,看网上很多人的暴力法,最多的也不过是O(N^3),
但是我当时却写了O(N^4),(手动哭泣)。
后来在Leetcode上面又看到了这道题
(https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/)
于是下决心来研究一下,终于弄个明白了。
这里我主要介绍两个算法(暴力法就不说辽~)
1. 滑动窗口法
先选定start何end两个指针(这里的指针代表位置),均从第一个字符开始,向后移动end,如果end和从start到end这段的字串的每一个字符都不相同,则继续向后移,直至出现相同或者end到达字符串末尾,并随时记录长度。
若出现相等,(重点来了,敲黑板了),假设是位置i和end相等了,这时我们就要先将start移动到i+1的位置。
为什么要这么做呢,我们来想一下,这种情况会不会漏掉什么?现在是i和end重了,现在无论我们把start放在start到i的任何一个位置,都改变不了冲突的事实,所以我们就直接将start放在i+1的位置上来重新弄这个字串。
记录下这个新字符串的长度,然后将新串的长度与原来的长度比较,选择下较长的那个。并继续循环,最后输出的就是最长的长度了。

基本的逻辑已经讲完了,下面我们来看代码和一些细节。

class Solution
{
public:
    int lengthOfLongestSubstring(string s)
    {
        int start = 0, end = 0, length = 0, maxlen = 0;
        while(s[end] != 0)
        {
            for (int index = start; index < end; index++)
            {
                if (s[end] == s[index])
                {
                    start = index + 1;//一定要先移动,再计算长度,因为计算的是新串的长度。
                    length = end - start; //这里长度会少一个,不过下面补上
                    break;
                }
            }
            end++;
            length++;//end移位时就加一个长度,顺便也补上了特殊情况差的长度了
            maxlen = maxlen > length?maxlen:length;
        }
        return maxlen;
    }
};

基本细节都再代码上写出来了。
2. 哈希表法
哈希表法的基本思路和方法一差不多,差别就在遍历字串时采用了哈希表,这样就把遍历的时间复杂度降到了O(1)。
实现方法是用unordered_map。
头文件#include<unordered_map>
它的key就是用哈希表存储的,至于哈希表的对应关系则已经被封装了,我们看不见,但是并不影响我们使用。
用key来存储字符,用T来存储字符的位置。
下面直接上代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int start = 0,end = 0,maxlen = 0,length = 0;
        unordered_map<char, int> hash;//创建hashmap
        while(s[end] != 0){
            if(hash.find(s[end]) != hash.end() && hash[s[end]] >= start){
                //后一个比较是为了防止出现过了,但已经不再当前子串中的产生bug
                start = hash[s[end]] + 1;
                length = end-start;
            }
            hash[s[end]] = end;//记得实时更新哈希表
            end++;
            length++;
            maxlen = maxlen > length?maxlen:length;
        }
        return maxlen;
    }
};

唯一要注意的就是
hash[s[end]] >= start
这个部分,为什么要加上这个部分呢?
举个例子
adbcbd
第一个冲突的是b所以start是放到b,这时如果end到了字符d的话,没有这一部分的话,前面已经有d了,如果不加这个判定,则d已经再哈希表中了,会产生错误,所以一定要加上这一条。

呼~
以上就是这道题的解法了,溜了溜了…

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!