快排的划分,归并排序的归并,之后的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 }