15.最长连续不重复子序列

快排的划分,归并排序的归并,之后的kmp都是双指针算法。 

双指针算法的两大类:

指向两个区间或指向一个区间

 双指针算法一般是这样的

 双指针算法运用了某些单调性质,可以将暴力的O(n^2)优化到O(n)

先来一个小的问题热身,输入一行若干个用空格隔开的单词,然后依次每行输出一个单词。具体应用看这里https://www.cnblogs.com/fx1998/p/12868788.html

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int main() {
 4     char str[1010];
 5     cin.getline(str, 1010);
 6     int len = strlen(str);
 7     //cout << len << endl;
 8     for (int i = 0; i < len; i++) {
 9         int j = i;
10         //每一次i循环的时候,都保证i是指向单词的第一个位置
11         while (j < len && str[j] != ' ') { //只要j没有走到终点  
12             //然后我们要找到当前这个单词的最后一个位置    
13             j++;
14         }
15         //当while循环结束时,j就指向当前这个空格
16         //此时从i到j-1之间就是一个单词 
17         //这道题的具体逻辑 
18         for (int k = i; k < j; k++) {
19             cout << str[k];
20         } 
21         cout << endl;
22         i = j;
23         //cout << j << endl; 
24     }
25     return 0;
26 }

本题的样例解释

 答案是2 3 5

 注意这里说的连续是指位置连续

方法一:暴力做法

i是终点

j是起点

i - j + 1

 方法二:双指针算法

红颜色表示i

绿颜色表示j

j表示i往左最远可以走多远

然后发现性质:在i往右走的过程中,j不会往前走。是具有单调性的。

然后就可以优化了

我们只枚举i

j的话是每次看一下要不要往后走

如果有重复元素的话,就j++

一直移动到j和i之间没有重复元素为止

所以最多是i走n步,j走n步,一共走2n步

时间复杂度从n^2优化到n

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 100010;
 4 int a[N], s[N];
 5 //a是原来的数
 6 //s是每个数出现的次数 
 7 int main() {
 8     int n;
 9     cin >> n;
10     for (int i = 0; i < n; i++) {
11         cin >> a[i];
12     }
13     int res = 0; //res表示答案 
14     for (int i = 0, j = 0; i < n; i++) {
15         s[a[i]]++; //每次加入一个数 
16         while (j <= i && s[a[i]] > 1) { //因为新加了一个数,然后有重复了,所以重复的一定是新加的数 
17             s[a[j]]--; //把它拿出去 
18             j++;
19         }
20         //while循环结束之后,j到i之间就没有重复元素了 
21         res = max(res, i - j + 1);
22     }
23     cout << res << endl;
24     return 0;
25 }
原文地址:https://www.cnblogs.com/fx1998/p/12824375.html