1. 程式人生 > 實用技巧 >15.最長連續不重複子序列

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 }