GitHub-LT-03-源码 :large_blue_diamond:哈希表 :large_blue_diamond:最长子串 :large_blue_diamond:重复元 :large_blue_diamond:滑动窗口
问题描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
解法1: 死窗口-便于理解
- 执行用时:1604 ms, 在所有 C++ 提交中击败了5.00%的用户
- 内存消耗:230.3 MB, 在所有 C++ 提交中击败了10.55%的用户
算法复杂度
O(n*n)
双重循环
class Solution {
public:
int lengthOfLongestSubstring(string s) {
//* 窗口思想解决-涉及到连续的一段数据元素 -> 死窗口 O(n*n) 但容易理解
//* 因为要求不重复 ->集合
size_t size = s.size();
unordered_set<char> windows;//* 最终结果,最长的子串窗口
for (size_t i = 0; i < size; i++) {//* i指向当前需要处理的字符串的开始
unordered_set<char> temp;//* 临时用于比较windows的大小的窗口
temp.insert(s[i]);//* 添加到临时的窗口
//* 看当前情况下 最大的窗口多大
//* 如果大于初始窗口的size,那么窗口替换成最大的窗口
//* 如果小于等于,则不进行操作
int j = i + 1;//* 下一个元素
while (j < size) {
if (!temp.insert(s[j]).second){
break;//* 插入不了 说明重复,跳出循环
}
else {
j++;//* 如果能够插入,则判断下一个元素是否重复
}
}
//* 比较
if (windows.size() < temp.size()) {
windows.clear();
windows = temp;
temp.clear();
}
}
return windows.size();
}
};
解法2 采用滑动窗口 - 参考官方解法
- 执行用时:56 ms, 在所有 C++ 提交中击败了40.26%的用户
- 内存消耗:11 MB, 在所有 C++ 提交中击败了43.22%的用户
算法复杂度
O(n)
只需遍历一遍即可
class Solution2 {
public:
int lengthOfLongestSubstring(string s) {
//* 让窗口滑动起来
int size = s.size();
unordered_set<char> windows;
int result = 0;
int wind_right = -1;//* 下一个元素
for (int i = 0; i < size; i++) {//* i指向当前需要处理的字符串的开始
if (i != 0) {
//* 因为是要从下一个字符开始,所以要移除已有窗口的开始字符
windows.erase(s[i - 1]);//* 相当于窗口向右滑动了一格
}
//* 滑动了窗口 => 新窗口
//* 判断右边界的下个字符是否在窗口内,如果在,则增大窗口即右边界向右扩大一个
//* 否则说明此时有重复,窗口停止扩张
while (wind_right+1 < size && !windows.count(s[wind_right+1])) {
windows.insert(s[wind_right+1]);
wind_right++;
}
//* 每次进行比较窗口尺寸和之前的哪个大
result = max(result, wind_right + 1 - i);
}
return result;
}
};
:triangular_flag_on_post: TODO
- :question: 解法2的算法分析,为啥就直接O(n)了