双指针算法
对于两重for循环
for(int i = 0; i < n; ++i)
    for(int j = 0; j < n; ++j)
    {
        //具体代码
    }//O(n^2)
双指针算法的思想就是:寻找指针i 与 j 之间是否有单调的关系。若存在,则利用此关系来把整个枚举的状态数量从O(n^2)降到O(n),模板如下
for(int i = 0, j = 0; i < n; ++i)
{
    while(j < i && check(j, i)) ++j;//此行为降低时间复杂度的关键。check()函数反映指针i与j的性质
    //每道题目的具体逻辑
}
最典型的应用如下:
给你一个英文字符串,找到每一个单词并逐行输出
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
/**
 * 把一个字符串中的所有单词找到,并按行输出
 * */
int main()
{
    char str[100];
    gets(str);
    int n = strlen(str);
    for(int i = 0; i < n; ++i) cout << str[i];
    cout << '\n';
    
    for(int i = 0; i < n; ++i)
    {
        int j = 0;
        while(j < i && str[j] != ' ') ++j;
        
        //双指针算法的具体逻辑部分
        for(int k = i; k < j; ++k)
            printf("%c", str[k]);
        cout << '\n';
    }
}
当然了,往往会卡在这个j与i指针之间的关系并不好找
最长连续不重复子序列
给定一个长度为n的整数序列,请找出最长的不包含重复数字的连续区间,输出它的长度。
输入格式
第一行包含整数n。
第二行包含n个整数(均在0~100000范围内),表示整数序列。
输出格式
共一行,包含一个整数,表示最长的不包含重复数字的连续子序列的长度。
数据范围
1≤n≤100000
具体解题思路:运用桶排思想,用数组s[]来记录每个输入的数字a[i]出现的次数,当s[a[i]]出现的次数大于1时,[j, i]区间构成的子序列就必定有重复元素,因此我们只能通过右移j指针,来试图在[j, i]区间中找到这个重复的元素并将其排除(s[a[i]]--; ++j;)每次j指针右移我们都需要检查一下s[a[i]]是否已经等于1(数字a[i]是否仅在新的区间[j, i]中出现一次)来判断是否停止移动j指针
具体代码如下
#include <iostream>
#include <string>
using namespace std;
const int N = 100010;
int n;
int a[N], s[N];//桶排序思想,当数据范围过大时应该用哈希表来求解
int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for(int i = 0; i < n; ++i) cin >> a[i];
    int len = 0;//记录最长连续子序列
    for(int i = 0, j = 0; i < n; ++i)
    {
        s[a[i]]++;
        while(/*j <= i&& 没必要写*/s[a[i]] > 1)//当s[a[i]]出现的次数大于1时,[j, i]区间构成的子序列就必定有重复元素
        {
            s[a[j]]--;
            j++;
        }
        len = max(len, i - j + 1);
    }
    cout << len << endl;
}
声明:acWing课程学习总结
作者:DriftingAE86
 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号