题目如下:
当时脑子抽了没有看到下面的规定
也就是说,除了英文字母,还有数字和字符串、符号、空格。刚开始以为只有英文,就用了哈希表法做,通过了800多个案例,有100个没通过才意识到自己大概是看漏条件了。
方法一 仅提供思路 map表键值对
下面是我用哈希表法解题的思路,这个方法也可以扩展到所有字符,只需要把表扩展就行了,我只是记录一下这种思路,以下代码并不是答案。
class Solution {
public:
int lengthOfLongestSubstring(string s){
int len=0;//记录目前最长字串长度
int len2=0;//记录当前字符串长度
map<int,int> mp;//记录当前存在的字符
for(int i=0;i<26;i++){
mp[i]=-1;//如果当前字串没有出现该字符,默认为-1
}
for(int i=0;i<s.size();i++){
if(len<len2){
len=len2;//如果当前字符长度大于最长,最长长度改变
}
char zifu=s[i];//当前字符
if(mp[zifu-'a']==-1){//判断当前字符是否在字串中出现,未出现
mp[zifu-'a']=i;//设置出现的先后顺序
len2++;//当前字串长度+1
continue;
}else{
int num=mp[zifu-'a'];//记录下重复字串的位置
for(int j=0;j<26;j++){
if(mp[j]!=-1&&mp[j]<=num){//在其前面的字串全部改为未出现
len2--;
mp[j]=-1;
}
}
mp[zifu-'a']=i;//将当前字符存入
len2++;
}
}
return len;
}
};
方法二 滑动窗口
代码可以改进,但发现解法中用的滑动窗口,而且更简单,便直接去学习新方法了。官方解答如下:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
// 哈希集合,记录每个字符是否出现过
unordered_set<char> occ;
int n = s.size();
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
int rk = -1, ans = 0;
// 枚举左指针的位置,初始值隐性地表示为 -1
for (int i = 0; i < n; ++i) {
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.erase(s[i - 1]);
}
while (rk + 1 < n && !occ.count(s[rk + 1])) {
// 不断地移动右指针
occ.insert(s[rk + 1]);
++rk;
}
// 第 i 到 rk 个字符是一个极长的无重复字符子串
ans = max(ans, rk - i + 1);
}
return ans;
}
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-by-leetc-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
unordered_set是STL的一种容器,具体使用可以参考以下文章c++ unordered_set详细操作_好人好事代表nxx的博客-CSDN博客
具体思路如下:在字符串左边同时放左指针和右指针,右指针不断向右移动,并将遇到的字符加入到unordered_set容器中。当unordered_set容器中出现两个相同元素时,左指针移动,不断删除元素,直到不存在两个相同元素为止。而后继续移动右指针,循环往复。在这过程中,记录下unordered_set容器的最大值,该最大值也就是不重复字串的最大值。
方法三 动态规划
该问题如果一直从左往右(或从右往左),可以拆解为一个一个的子问题进行分析。假设为从左往右,毫无疑问,第一个最大字串就是最左边元素,长度记为1。
从左往右遇到第二个字符,会出现两种情况:1.其与第一个元素相同2.与第一个元素不同
一直推,直到第n个元素,也同样是两种情况:
1.第n个元素向左的最大字串与第n-1个元素的最大字串不存在重复元素,其最大字串也就是第n-1个元素的最大字串加一。
2.第n个元素向左的最大字串与第n-1个元素的最大字串存在重复元素,第n个元素向左的最大字串要重新计算。
如下是我自己编写的使用动态规划的代码,该代码使用了辅助数组,利用第n-1项得到的答案去推算第n项的答案。动态规划构思也非常巧妙,我也是参考了左程云老师的思路。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int maxlength=1;
if(s==" ")//特例
return 1;
if(s=="")//特例
return 0;
int p[s.size()];//辅助数组,记录第n-1个字符的最大不重复字串
int tag=0;
p[0]=1;
for(int i=1;i<s.size();i++){//从左向右,当前位置为i
for(int j=i-p[i-1];j<i;j++){//看第i-1的的最大字串是多少(p[i-1]),并从i-p[i-1]一直到i-1查看有没有与s[i]重复的字串,有的话重新计算,没有的话直接+1.
if(s[i]==s[j])//存在重复串,该重复串的下标为j
{tag=1;//标记
p[i]=i-j;//记录下第n个字符的不重复字串最大长度
maxlength=max(maxlength,p[i]);
}
}
if(!tag){//没有重复串
maxlength=max(p[i-1]+1,maxlength);//最大长度为当前最大长度,或最新的
p[i]=p[i-1]+1;//记录下第n个字符的不重复字串最大长度
}
tag=0;
}
return maxlength;
}
};