无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

 

示例 :

输入: "pwwkew"

输出: 3

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

暴力解法:

对于每一个子串都进行检验(通过调用allUnique)子串中是否有重复字符,只对没有重复字符的子串进行计算长度,返回最长长度。

获取子串的方式就是通过嵌套两个for循环,这很容易理解。

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         int n=s.size();
 5         int maxLength=0;
 6         for(int i=0;i<n;i++)
 7             for(int j=i+1;j<n;j++)
 8             {
 9                 if(allUnique(s,i,j))
10                     maxLength=maxLength>(j-i+1)?maxLength:(j-i+1);
11             }
12         return maxLength;
13     }
14     bool allUnique(string s,int start,int end)//用于判断子串中是否含有重复字符
15     {
16         set<int> Set;//关键字不可重复的关联容器
17         for(int i=start;i<=end;i++)
18              Set.insert(s[i]);
19         if(Set.size()<(end-start+1))//说明子串有重复字符
20             return false;
21         return true;            
22     }
23 };

 滑动窗口:

滑动窗口的思想就是始终维持窗口只包含有不重复的字符。窗口的左边界和右边界都可以向移动,当添加一个元素,若元素与窗口里的元素都不同,则窗口右边界向右移动一格;如果窗口里面已经有该元素,则移动左窗口边界使窗口里面没有重复字符。比如字符串为abcbd,则窗口依次为:

a

ab

abc

cb//添加进b重复了,所以左边界移到原来的b后面,使窗口没有重复字符,即c处

cbd

 

用max来记录窗口的最大长度,每移进来一个字符,都要检查maxLength是否要修改

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         int max = 0;
 5         int i = 0;//窗口左边界
 6         int size = s.size();//字符串s的大小
 7         for(int j = 0; j < size; j++)//j为窗口右边界
 8         {
 9             for(int k = i; k < j; k++)//用k来检查窗口内是否含有重复字符
10             {
11                 if(s[k] == s[j])//发现有重复字符
12                 {
13                     max = max > (j-i) ? max : j-i;
14                     i = k+1;//修改左边界
15                 }
16             }
17             max = max > (j-i+1) ? max : j-i+1;//检查max是否要更新
18         }
19         return max;
20     }
21 };

 

利用hashmap来优化查找是否有重复字符时的时间,用的还是滑动窗口的思想

保存在unorder_map关联容器里的元素是无序不重复的

unordered_map<char,int>umap     umap的关键字为添加进来的字符,值为添加进来时的end值,目的是用来表示序号,便于改变窗口左边界start的值,因为有重复字符时,start会变。比如字符串abcde,那么值分别为01234;

start为窗口左边界,end为窗口右边界,maxLength记录窗口大小

往umap里添加字符,当有无重复字符的时候,就直接把它添加进去,值为end,即umap[s[end]]=end;

当umap里已经有重复字符时,就修改start的值为start[s[end]]+1,也就是重复字符后面的一位了。还要修改umap[s[end]]的值为end,因为如果后面还遇到相同的这个字符,那么start的修改才会正确,否则start会出错。

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         int start=0;int end=0;
 5         int n=s.size();
 6         int maxLength=0;
 7         unordered_map<char,int> umap;
 8         while(end<n)
 9         {
10             if(umap.find(s[end])!=umap.end()&&umap[s[end]]>=start)//umap从start开始里有重复的字符
11             {
12                 start=umap[s[end]]+1;
13                 umap[s[end]]=end;//注意修改umap[s[end]]的值
14                 maxLength=maxLength>(end-start+1)?maxLength:(end-start+1);
15             }
16             else//无重复字符
17             {
18                 umap[s[end]]=end;
19                 maxLength=maxLength>(end-start+1)?maxLength:(end-start+1);      
20             }
21             end++;
22         }
23         return maxLength;
24     }
25 };

 



posted @ 2020-04-22 18:17  江雨牧  阅读(241)  评论(0)    收藏  举报