1、题目描述
找出一个字符序列中一个最长的包含不重复字符的子字符串,比如在字符串“arabcacfr”中,最长的不含重复字符的子字符串是“acfr”,长度为4。
2、解题思路
(1)暴力破解
使用暴力法可以在O(n^2)的时间复杂度内找到字符序列的所有字符串,然后在O(n)的时间复杂度内比较这个字符串是否包含重复字符,因为暴力解的时间复杂度为O(n^3),如果面试用暴力解,基本上就凉凉了。
(2)使用滑动窗口
从头到尾遍历数组元素时,使用一个辅助字典来保存已经找到的元素次数。同时使用一个pos变量来保存滑动窗口的起始位置,用一个变量temp_len来保存滑动窗口的大小,用变量start保存最后所求的窗口的起始位置,用变量max_len来保存窗口的最大长度。遍历过程中,如果这个元素在map中没有出现过,则这个元素在map中的次数设为1,同时计算滑动窗口temp_len的大小,如果滑动窗口temp_len比最大窗口max_len大,则把max_len=temp_len,同时start=pos。如果这个元素在map中已经出现过,那么start指针往后移动到重复元素的下一个元素,移动中划过的元素在map中的次数设置为0,时间复杂度O(n^2)。详细代码如下:
#include<iostream>
#include<vector>
#include<map>
using namespace std;
//找出最长不含重复字符的子字符串
void MaxNorepeatSeq(vector<char> input) {
map<char, int> has_found_char;
int pos = 0; //保存滑动窗口的起始位置
int max_len = 1; //保存最终所求的窗口大小
int temp_len = 1; //保存滑动窗口的临时大小
int start = 0; //保存最终所求滑动窗口的起始位置
has_found_char[input[0]] = 1; //保存已经找到的数组中连续元素的次数
for (int i = 1; i < input.size(); i++) {
if (has_found_char[input[i]] == 0) {
has_found_char[input[i]] = 1;
temp_len = i - pos + 1;
if (max_len <= temp_len) {
max_len = temp_len;
start = pos;
}
}
else {
has_found_char[input[i]]++;
while (has_found_char[input[pos]] != 2 && pos < i) {
has_found_char[input[pos]] = 0;
pos++;
}
pos++;
has_found_char[input[i]] = 1;
}
}
cout << "start:" << start << endl;
cout << "max_len:" << max_len << endl;
}