双指针题目选做

NC18386 字符串

这道题几乎就是双指针的模板题了。

每次移动一下左端点,然后移动右端点知道满足条件

#include<bits/stdc++.h>

using namespace std;

int v[300] = {};

int32_t main() {
    string s;
    cin >> s;
    int l = 0 , r = -1 , len = s.size() , ans = 1e9 , k = 0;
    while( l < len ){
        while( r < len - 1 && k < 26 ) { // 右指针右移
            r++, v[s[r]]++;
            if (v[s[r]] == 1) k++;
        }

        if( k == 26 ) ans = min( ans , r - l + 1 ); // 满足条件

        if( v[s[l]] == 1 ) k --; // 左指针右移
        v[s[l]] -- , l ++;
        }
    cout << ans << endl;
    return 0;
}

NC207040 丢手绢

这道题也可以用双指针来做。但是值得注意的是因为圆的性质,所以圆上两点之间的距离一定是小于等于半径的。所以如果右指针移动后距离大于半径了,右指针的移动就可以结束了。

#include<bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

const int N = 1e5+5;
int n , a[N] , ans , sum , cnt ;

int32_t main() {
    n = read();
    for( int i = 0 ; i < n ; i ++ )
        a[i] = read() , sum += a[i];
    for( int i = 0 , j = -1 ; i < n ; i ++ )
    {
        while( cnt * 2 < sum ){
            j = ( j +1 ) % n , cnt += a[j];
            ans = max( ans , min( cnt , sum - cnt ) );
        }
        cnt -= a[i];
    }
    cout << ans << endl;
    return 0;
}

luogu P1102 A-B 数对

这道题主要运用了双指针的方法来写,但是需要运用一些 hash 的思想

在 map 中枚举两个指针,一直移动右指针直到r-l>=c然后判断是否相等,相等就更新答案

#include<bits/stdc++.h>
#define int long long
using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

const int N = 1e5+5;
int n , c , cnt;
map< int , int > a;

int32_t main() {
    n = read() , c = read();
    for( int i = 1 , x ; i <= n ; i ++ )
        x = read() , a[x] ++;

    for( auto i = a.begin() , j = i ; i != a.end() && j!= a.end() ; i ++ ){
        while( j != a.end() && j->first - i->first < c ) j ++ ;
        if( j->first - i->first == c )
            cnt += i->second * j->second;
    }
    cout << cnt << endl;

    return 0;
}

luogu P1638 逛画展

比较裸的双指针问题,每次维护一下区间内画的种数就好了

#include<bits/stdc++.h>
using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

const int N = 1e6+5 , M = 2e3+5;
int n , m , a[N] , cnt , ansl , ansr , ans = 1e9;
int vis[N];

int32_t main() {
    n = read() , m = read();
    for( int i = 1 ; i <= n ; i ++ )
        a[i] = read();
    for( int l = 1 , r = 0 ; l <= n ; l ++ ){

        while( r < n && cnt < m )
            r ++ , vis[ a[r] ] ++ , cnt += (vis[ a[r] ] == 1 );
        if( cnt == m && ans > r - l + 1 )
            ans = r - l + 1 , ansl = l , ansr = r;

        cnt -= ( vis[ a[l ] ] == 1 ) , vis[ a[l] ] --;
    }
    cout << ansl << " " << ansr << endl;
    return 0;
}

luguoP1381 单词背诵

这道题首先要判断那些单词是不用背的,需要背的单词有多少个,然后用双指针维护出最短的区间。

注意如果需要背的有0 个,那么区间也一定是0

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5+5 , M = 1005;
map< string , int > hs;
int n , m , a[N] , ans = 1e9;
int vis[N];
string cur;


int32_t main() {
    cin >> n;
    for( int i = 1 ; i <= n ; i ++ )
    {
        cin >> cur;
        hs[cur] = i;
    }
    cin >> m;
    for( int i = 1 ; i <= m ; i ++ )
    {
        cin >> cur;
        if( hs.find(cur) == hs.end() ) a[i] = -1;
        else a[i] = hs[ cur ] , vis[ a[i] ] = 1;
    }

    int t = 0;
    for( int i = 1 ; i <= n ; i ++ )
        t += vis[i] , vis[i] = 0;
    cout << t << endl;
    if( t == 0 )
        printf("0\n") , exit(0);
    for( int l = 1 , r = 0 , cnt = 0 ; l <= m ; l ++ ){
        while( r < m && cnt < t ){
            r ++ ;
            if( a[r] == -1 ) continue;
            vis[ a[r] ] ++ , cnt += ( vis[a[r]] == 1 );
        }
        if( cnt == t && r - l + 1 < ans )
            ans = r - l + 1 ;

       if( a[l] != -1 ) cnt -= ( vis[ a[l] ] == 1 ) , vis[ a[l] ] --;
    }
    cout << ( ans == 1e9 ? 0 : ans ) << endl;
    return 0;
}
posted @ 2022-07-05 15:21  PHarr  阅读(29)  评论(0编辑  收藏  举报