算法

  • 枚举

  •  前缀和,差分

前缀和:sum[ i ] = a[ i ] + sum[i - 1]  前 i 个数的求和。

差分:delta[ i ] = a[ i ] - a[ i -1 ] 第 i 个数 - 第 i-1 个数。

例题:https://ac.nowcoder.com/acm/problem/16649

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 /**
 4 对于区间问题,简化成区间端点的问题;
 5 比如: 前缀和 或者 差分,利用端点既可以维护整个数组,降低时间复杂度
 6 */
 7 int L,M,cnt;
 8 int delta[10010]; //差分数组
 9 
10 int main()
11 {
12     cin>>L>>M;
13     while(M--)
14     {
15         int l,r;
16         scanf("%d%d",&l,&r);
17         if(l>r) swap(l, r);
18         delta[l]++;    //更新差分数组的值
19         delta[r+1]--;
20     }
21     int a=0;//只需要单个的a就可以得到a[i]每一个位置的值,但我们不需要保存,只需要判断a[i]==0即可
22     for(int i=0;i<=L;i++)
23     {
24         a+=delta[i];
25         if(a==0)
26             cnt++;
27     }
28     cout<<cnt;
29     return 0;
30 }     

 本题目可以加强数据:升级版:如果数据量1<L<=10^9,1<=m<=10^5。此时需要离散化。

 

#include<bits/stdc++.h>
using namespace std;
/**
对于区间问题,简化成区间端点的问题;
比如: 前缀和 或者 差分,利用端点既可以维护整个数组,降低时间复杂度
升级版:如果数据量1<L<=10^9,1<=m<=10^5
升级版解法:差分,但是需要离散化记录每一个间隔的端点“位置”以及“加一or减一”
*/
int L,M,cnt;
struct ty{//差分数组结构体
    int pos,num;
}delta[200010];
bool comp(ty a,ty b)
{
    if(a.pos==b.pos) return a.num<b.num;
    return a.pos<b.pos;
}
int main()
{
    int l,r;
    cin>>L>>M;
    for(int i=1;i<=M;i++)
    {
        scanf("%d%d",&l,&r);
        delta[i].pos=l;
        delta[i].num=+1;
       
        delta[i+M].pos=r+1;
        delta[i+M].num=-1;
    }
    sort(delta+1,delta+1+2*M,comp);
    int a=0;//只需要单个的a就可以得到a[i]每一个位置的值,但我们不需要保存,只需要判断a[i]==0即可
    for(int i=1;i<=2*M;i++)
    {
        //cout<<i<<" "<<delta[i].pos<<endl;
        a=a+delta[i].num;
        if(a==1&&delta[i].num==1)
            cnt=cnt+delta[i].pos-delta[i-1].pos;
    }
    cnt=cnt+L-delta[2*M].pos+1;
    cout<<cnt;
    return 0;
        
}
  •  尺取法

https://ac.nowcoder.com/acm/contest/20960/1027

尺取法右指针在满足条件的时候停止移动(即while循环的第二个条件),此时移动左指针,
直到不满足条件(即不满足while循环的第二个条件,此时!solve()=true),停止左指针移动,
再继续移动右指针,右指针最终停止条件为走到末尾(即while第一个条件)。
模板如下:
for (l=0,r=-1;l<n;l++)
    {
        while(r<n-1&&!solve())//!solve()为关键--->即找到合法结果solve()=true,停止移动。
        {
            r++;
            //按要求处理
            //used[s[r]-'a']++;
        }
        if(solve())
            {
            ans=min(ans, r-l+1);
            }
        //按要求处理
        //used[s[l]-'a']--;
    }        
 
 
/**尺取法
尺取法右指针在满足条件的时候停止移动(!solve()此时=false),此时移动左指针,
直到不满足条件(!solve()此时=true),停止左指针移动,再继续移动右指针
右指针最终停止条件为走到末尾。
**/
#include <bits/stdc++.h>
using namespace std;
int used[30];
bool flag;
int l,r,ans=1e6+10;
bool solve()
{
    for (int i=0;i<26;i++)
        {
            if(used[i]==0)
                return false;
        }
    return true;
}
int main()
{
    string s;
    cin>>s;
    int n=s.size();
    ans=n;
    for (l=0,r=-1;l<n;l++)
    {
        while(r<n-1&&!solve())//!solve()为关键--->即找到合法结果solve()=true,停止移动。
        {
            r++;
            used[s[r]-'a']++;
        }
        if(solve())
            {ans=min(ans, r-l+1);
            //cout<<ans<<endl;
            }
        used[s[l]-'a']--;
    }
    cout<<ans;
    return 0;
}
  •  归并排序

 

 

posted @ 2023-06-27 21:15  ACtoYou  阅读(48)  评论(0)    收藏  举报