#include <iostream>
#include <string>
#include <unordered_set>
#include <algorithm>
using namespace std;
int lengthOfLongestSubstring(string s) {
size_t n = s.length(); // 使用 size_t 类型来匹配字符串长度的类型
unordered_set<char> charSet;
int maxLength = 0, left = 0, right = 0;
while (right < n) {
// 如果字符已经在集合中,移动左指针,缩小窗口直到窗口内不含重复字符
while (charSet.count(s[right])) {
charSet.erase(s[left]);
left++;
}
// 将当前字符加入集合
charSet.insert(s[right]);
// 更新最大长度
maxLength = max(maxLength, static_cast<int>(right - left + 1));
// 移动右指针扩大窗口
right++;
}
return maxLength;
}
int main() {
string s;
cout << "Enter a string: ";
getline(cin, s); // 使用 std::getline 获取用户输入的字符串
int result = lengthOfLongestSubstring(s);
cout << "Length of the longest substring without repeating characters: " << result << endl;
return 0;
}
滑动窗口
如果没有很直观的理解可以先从暴力入手
#include <iostream>
#include <string>
#include <unordered_set>
using namespace std;
int lengthOfLongestSubstring(string s) {
int maxLength = 0;
int n = s.length();
// 遍历所有可能的子串
for (int i = 0; i < n; ++i) {
unordered_set<char> charSet;
for (int j = i; j < n; ++j) {
// 如果当前字符已经在集合中,说明有重复字符,结束内层循环
if (charSet.count(s[j])) {
break;
}
// 否则将当前字符加入集合中
charSet.insert(s[j]);
// 更新最大长度
maxLength = max(maxLength, j - i + 1);
}
}
return maxLength;
}
int main() {
string s = "abcabcbb";
cout << lengthOfLongestSubstring(s) << endl; // 输出:3
s = "bbbbb";
cout << lengthOfLongestSubstring(s) << endl; // 输出:1
s = "pwwkew";
cout << lengthOfLongestSubstring(s) << endl; // 输出:3
return 0;
}
这两个代码特点都是运用了哈希表存储来判别是否存在重复的字符,滑动窗口则是更高效,并且是双指针遍历并且是动态进行。
下面是对滑动窗口的一些讲解
滑动窗口算法通常被视为双指针技术的一种动态应用形式。虽然“滑动窗口”和“双指针”可以用于描述不同的场景,但它们有许多共同点和重叠的地方。以下是对两者的解释及其联系:
双指针技术
双指针技术涉及在数据结构中使用两个指针,常见于解决以下类型的问题:
- 两个指针向中间收敛:如在排序数组中查找两数之和、反转字符串等。
- 一个指针遍历,一个指针调整:如在链表中查找倒数第k个节点等。
滑动窗口技术
滑动窗口是一种动态的双指针应用,特别适用于处理连续子数组或子串的问题。滑动窗口技术通过调整窗口的起点和终点来动态地包含或排除元素,从而满足特定的条件。滑动窗口的两个边界可以看作是两个指针,这些指针可以独立移动以扩大或缩小窗口。
"滑动指针"通常可以被理解为一种特殊的"双指针"技术。虽然这两者的名字有所不同,但它们的核心思想和实现方式非常相似,都是通过调整指针或窗口的位置来解决问题。
滑动指针与双指针的联系和区别
-
滑动指针:
- 滑动指针可以看作是一种更为灵活的双指针技术,通常用于处理连续子数组或子串的问题。
- 它的动态性体现在可以根据具体问题,每次移动一个窗口的起始或结束位置,来寻找最优解。
- 滑动指针的移动不一定是每次移动一个固定步长,而是根据问题需要在集合中移动窗口边界。
-
双指针:
- 双指针通常指的是同时在数据结构中移动两个指针,例如数组或链表。
- 这两个指针通常用于解决某些特定类型的问题,如反转数组、查找两数之和等。
- 在双指针技术中,指针的移动往往是固定的步长,并且往往是沿着数据结构的方向进行移动。
维护滑动指针的基本方法
维护滑动指针的关键是根据问题的要求,调整窗口的大小和位置,以便在数据结构中找到所需的子数组或子序列。以下是一般情况下维护滑动指针的方法:
- 初始化:定义需要用到的指针和集合(或其他适合的数据结构)。
- 移动窗口:
- 根据问题的要求,移动窗口的起始或结束位置。
- 根据集合的变化(添加或删除元素),来动态调整窗口的大小和位置。
- 更新状态:根据窗口的变化,计算或更新所需的状态或结果。
具体来说,如果需要动态调整滑动窗口的指针,可以根据当前集合中的情况,适时地移动窗口的边界。例如,在求解最长不含重复字符的子串时,如果发现重复字符,可以移动窗口的起始指针,直到窗口内不再有重复字符。