题号0003 无重复最长子串
题目地址 https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
题目目的很明确,一个子串中不含重复字符,找到最长的子串,计算长度。
基本想法:一次遍历,定义了两个索引,起始位置和结束位置,如果当前遍历(结束位置)的字符已经出现过,就更新起始位置,重新计算长度。
- 第一次提交:
Step 1 定义了两个索引,分别代表字符串开始(indexBegin)和(indexEnd)
Step 2 外循环遍历每个字符,索引为indexEnd
Step 3 内循环从起始位置indexBegin,遍历到indexEnd,检测
之间每个字符与外循环的indexEnd的字符是否重复;
Step 4 如果字符重复,将indexBegin更新到内循环索引i+1的位置,作为下次内循环的开始;
int lengthOfLongestSubstring1(string s) {
int retMaxLen = 0;
int indexBegin = 0;
int indexNext = 0;
for(indexNext = 0; indexNext < s.length(); ++indexNext)
{
for (auto i = indexBegin;i <= indexNext; ++i)
{
auto begChar = s[i];
auto endChar = s[indexNext];
if((begChar == endChar) && (i != indexNext))
{
indexBegin = i + 1;
continue;
}
}
auto tempLen = indexNext - indexBegin + 1;
retMaxLen = max(retMaxLen, tempLen);
}
return retMaxLen;
}
结果:执行时间 20ms,内存消耗 9 MB。
结果看来,两层循环跑了987个用例果然耗时。
2.于是二次提交
查看了题解,明白了2个点:
1、这种起始索引,结束索引组成的就是“滑动窗口”,不断往后滑动,动态变动窗口大小;
2、如果想提升时间效率,自然需要空间换时间。原本第一次的方案:查找重复的字符的位置,这耗费时间。
于是第二次提交,使用hash表来记录字符的index。这里使用一个vector(128, -1),每个index代表字符的ASCII码,值为index。
int lengthOfLongestSubstring(string s) {
int retMaxLen = 0;
int indexBegin = 0;
int indexNext = 0;
vector<int> vecHasShowChar(128, -1); // 已经出现的字符的位置
for(indexNext = 0; indexNext < s.length(); ++indexNext)
{
char endChar = s[indexNext];
if(vecHasShowChar[endChar] != -1)
{
// 说明当前字符出现过
// 更新其实位置
indexBegin = max(indexBegin, vecHasShowChar[s[indexNext]] + 1);
}
// 计算最大长度
auto tempLen = indexNext - indexBegin + 1;
retMaxLen = max(retMaxLen, tempLen);
// 更新出现字符位置
vecHasShowChar[s[indexNext]] = indexNext;
}
return retMaxLen;
}
结果:执行时间 8ms,内存消耗 9.9 MB。
Github地址:https://github.com/saberqueen/LeetingCodeExcise.git