找最长子串的长度
问题描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
思路1:滑动窗口
这里以c/c++语言来具体化
- 找到一个字符串str[],可以用来存放所有可能
输入:abcabcbb
a,ab,abc,bca,cab,bc,b
-
用string类对字符串进行操作
- operator+ 字符串连接
- getline 从输入流读入一行
- substr 得到字符串
- find 查找
- begin 字符串的开头
- end 字符串的结尾
其他string类的操作,点击这里即可;
具体思路开始(可以参考下面几幅图)
- 在0,s.length区间循环
去除子字符串的重复字符
找位置,设置cursor游标 - 去除字符,提取子串substr(sursor+1)
增加子字符串的重复字符
代码
/*滑动窗口*/
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int len = 0; //最大长度
//int start = 0; //找上次重复字符的右边位置
int cursor = 0; //游标
int i=0;
string str = ""; //子字符串
for(i=0; i<s.length(); i++){
if(str.find(s[i]) == -1){ //是否重复字符
str = str + s[i];
len=str.length();
}
else{ //找到重复子串
if(len<str.length())
{
len = len>str.length() ? len : str.length(); //更改最大字串长度
//start = s.find_first_of(s[i], start) + 1;
}
cursor = str.find_first_of(s[i]); //在子串中查找重复位置
str = str.substr(cursor+1) + s[i]; //从重复字符处后一位置截取字符串
}
}
len = len>str.length() ? len : str.length();
//cout<<s.substr(start,len); //用于输出第一次出现的最大子串
return len;
}
};
修改之后,添加start来记录最大子串第一次出现的右边位置(删除三行//即可)
调用substr可以输出第一次出现的最大子串
思路2:哈希表
理解了上面的思路1之后,思路2就很好理解了
思路2主要使用了哈希表存放每一个元素的上一次重复的右边位置(可结合下图)
- max与i-left+1作比较(注:这里的max为上面的len,这里的left为上面的游标,这里的hash[s[i]]为上面的start,可以理解哈希表为start数组)
- left移动,并重新计算left与上一个重复数的右边位置
- left不移动的情况只有两种
- s[i]重复,且left>=hash[s[i]],游标不小于第i个位置下一个位置
- s[i]不重复hash[s[i]]=0
代码
/*哈希表*/
class Solution {
public:
int lengthOfLongestSubstring(string s) {
//设置字符数组
int hash[256]={0};//hash[s[i]]是s[i]上一次出现的位置+1
int i,left=0,max=0;
for(i=0;i<s.length();i++)
{
if(hash[s[i]]==0||hash[s[i]]<left)//判断left是否要移动
{
max=max>(i-left+1)?max:(i-left+1);//left不移动
}
else
{
left=hash[s[i]];
}
hash[s[i]]=i+1;//hash[s[i]]为是s[i]前一次出现的位置+1
}
return max;
}
};
这里的hash[s[i]]中的s[i]为字符的ASCII码值,这就可以理解为什么hash数组是256
当然也可以改成hash[s[i]-‘0’]这种形式,原理是一样的,笔者在devc++上都测试可用
如果本文对宝宝打开思路有帮助,可以点个赞哦~