读题心路历程:这道题意思感觉就是,给你一个字符串,然后找出无重复的最长字串,这个无重复的最长字串由题目来看包含两个特点:(1)无重复字母出现;(2)要是连续的。分析到这之后,脑海中就冒出了先遍历,然后定义个集合,利用集合可以find的优点,在遍历的过程中,把无重复的字符串存进集合,最后再size()一下集合的长度,整个一个okk。
但是自己写的过程中总是没法把例子全部跑对,还是结合了题解,进行了最终的代码编写。(这是现阶段没有办法的办法,好像还没有那个能力把自己的全部思路实现,标记一下,等回过头来,能力升上去了,再过来做这道题)
解题过程:
unordered_set<char> s1;//定义一个无序集合,这里不用set,也是因为set会自动排序的,不能用到这道题里
int left = 0;
int maxStr = 0;
//遍历题目给的字符串s
for(int i=0 ; i<s.size() ; i++)//
{
//这里只需要在遍历的过程中判断我们建的集合s1里边有没有字符串s中的字符s[i]
//这是我一开始的代码if(s1.count(s[i])==0){};
//这里只去判断一遍集合中是否有s[i],在正常解题的时候,就会遇到"pwwkew"例子过不了,仔细看一下就会发现原因,当s1中已经存进"pw"的时候,遍历到第s[2]的时候,就会发现s1中已经有w了,然后就erase掉s1的开头。在只判断一遍的情况下,这个时候s1里边实际存的是ww,这里就已经开始错误了。所以要在while循环里进行集合判断。
while(s1.count(s[i])!=0)//当s1中s[i]的数量不等于0的时候——s1中已经存在s[i]的时候
{
s1.erase(s[left]); //这里就涉及到滑动窗口这个解题方法了,这个滑动窗口我觉得就是把我们建立的集合s1看成是一个边界会变的窗口,不停的改变集合s1的内部元素的过程就是滑动窗口在字符串s上滑动的过程。所以这里是需要一个left左指针(滑动窗口左边界,用来控制集合s1的左边界元素)。所以这里的left初始值可以定义为0;left=0的时候,意思就是集合s1中开头元素就是字符串中的第一个元素,如果遍历过程中,出现重复字符串,这时left就要加1;left=1的意思就是,我现在要删除此时集合s1中的第一个元素,这个元素就是字符串s[1]元素。
left++;//这里left++的意思,显然就是在集合s1中的s[left]这个元素之后,需要让这个左指针指向s中的下一个元素了,所以要left++
}
//当判定集合s1中没有s[i]之后,这个时候就需要把s[i]插入到集合
s1.insert(s[i]);
//定义一个临时变量tmp用来存放集合s1的大小
int tmp = s1.size();
maxStr = max(maxStr,tmp);//这里是在移动序列s1的过程中,总会取得最大的值maxStr
}
return maxStr;
PS(补充知识点)文章参考:
set和unordered_set的不同:
1)set基于红黑树,set里边的元素是会进行自动排序的,而unordered_set是基于哈希表的,它是无序的,如下图(1)所示。
图(1)
2)set进行搜索、插入、删除操作的时间复杂度为O(logn)。unordered_set实现起来的时间复杂度为O(1),但是由于unordered_set是基于哈希表的,所以空间复杂度高于set 的。
如果需要自动排序集合就用set,不需要的话unordered_set的效率高。