给定一个字符串,找出不含有重复字符的最长子串的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 无重复字符的最长子串是 “abc”,其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 无重复字符的最长子串是 “b”,其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 无重复字符的最长子串是 “wke”,其长度为 3。
请注意,答案必须是一个子串,”pwke” 是一个子序列 而不是子串。
这道题算是入门的算法题了。。。。这道题都看了这么久,多谢 大神博客 提点,哎,菜是原罪。。。
下面说下大概思路
本题就是采取划窗机制,首先要一个map(或者其他的方法)保存每个字符出现过的位置,然后,设置一个头指针,就是左边界位置,然后向后遍历这个字符串,如果这个字符串中的字符没出现过,就保持这个左边界的位置不变,然后继续向后遍历,如果这个字符出现过,就把这个字符的位置拿出来看下,如果位置是在左边界的左边,则不用管,如果是在左边界的右边,就说明这个字符在左边界的后边出现过,现在又出现了一次,那就把左边界移动到上一次出现这个字符的位置,每次都更新这个长度(i-left+1)最后的结果就是最长的长度了。
coding 1:利用map
class Solution {
public:
int lengthOfLongestSubstring(string s) {
string str(s);
map<char, int> m_c_i;
for (int i = 0; i < str.length(); ++i) {
//初始化这个map
m_c_i[str[i]] = 0;
}
int left=0, result=0;
for (int i = 0; i < str.length(); ++i) {
if(m_c_i[str[i]]==0 || m_c_i[str[i]]<left){
//如果没出现过这个字符(值为0),或者上次出现的位置在left左侧,那么就计数
result = max(result, i-left+1);
}else{
//出现在left的右侧,则,更新left
left = m_c_i[str[i]];
}
//更新这个字符出现的位置
m_c_i[str[i]] = i+1;
}
return result;
}
};
coding 2: 利用长度为256的数组保存,因为ascii最多表示256个字符,这种方法比上面的方法快一点点
class Solution {
public:
int lengthOfLongestSubstring(string s) {
string str(s);
int point[256]={0}, result=0, left=0;
for (int i = 0; i < str.length(); ++i) {
if(point[str[i]]==0 || point[str[i]]<left){
result = max(result, i-left+1);
}else{
left = point[str[i]];
}
point[str[i]]=i+1;
}
return result;
}
};
coding 3:因为看到上面每次都在赋值,就想,干脆在变left的时候在赋值吧,可是事实是速度变慢了。。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
string str(s);
int point[256]={0}, result=0, left=0, exam=0;
for (int i = 0; i < str.length(); ++i) {
if(point[str[i]]==0 || point[str[i]]<left){
exam++;
}else{
result = max(result, exam);
//这个地方一定要注意,exam是暂时存放这轮的长度的参数,不能每次都设为1,要从截断的地方计数,
//比如:dvdf在检测到第二个d时,这里如果exam初始化为1,那么结果就是2了,因为v的长度没有算
//所以更新的时候要用i-point[str[i]]+1就是用d的位置减去上一个d的位置,再检测f即可
exam=i-point[str[i]]+1;
left = point[str[i]];
}
point[str[i]]=i+1;
}
result = max(result, exam);
return result;
}
};