算法基础----尺取法(双指针)

尺取法:也可称为双指针,是算法竞赛种常用的一个优化技巧,用来解决序列区间问题。

该方法主要有两种扫描方式:反向扫描和同向扫描

接下来以几道例题来解释

t1 回文判定(反向扫描)

算法基础----尺取法(双指针)_第1张图片

思路:反向扫描最直接的题目,直接上代码!

#include
using namespace std;
int main()
{
    string s;
    cin >> s;
    int flag=0;
    for(int i=0,j=s.size()-1;i

t2 日志统计(正向扫描) 

题目描述:

算法基础----尺取法(双指针)_第2张图片

 算法基础----尺取法(双指针)_第3张图片

 算法基础----尺取法(双指针)_第4张图片

思路:首先的一个难点在于数据的存取,这里我们先建立一个结构体数组来储存每个日志的ts和id,然后建立num数组来进行计数,建立flag数组来判断是否为热帖,接下来将每个日志按时间进行排序。最后使用双指针,用指针i来将每一个日志进行计数,用指针j来判断日志之间的间隔时间是否超过d

代码如下

#include
using namespace std;
const int N = 100005;
int num[N];    //num[i]:记录id=i的帖子的赞的数量
int flag[N];   //flag[i]:id=i的贴子曾是热帖
struct post{
    int id;
    int ts;
}p[N];                  //记录帖子
int cmp(post x,post y){ return x.ts < y.ts;  } //按时间从小到大排序
int main(){
    int n,d,k;
    cin>>n>>d>>k;
    for(int i=0;i>p[i].ts>>p[i].id;
    sort(p,p+n,cmp);    //按时间从小到大排序
    for(int i=0,j=0;i= d){ 
            num[p[j].id]--; //随着时间流逝,d之前的每个贴的次数都减1
            j++;
        }
        if(num[p[i].id] >= k)   //在区间[i-d,i)上达到k个赞
            flag[p[i].id]=1;
    }
    for(int i=0;i

t3 锻造兵器

算法基础----尺取法(双指针)_第5张图片

 算法基础----尺取法(双指针)_第6张图片

 思路:首先需要排序,由于这道题有重复的数字所以两个指针是不能满足条件的,因此我们要用三个指针用指针i来遍历每个锻造石,j和k来遍历锻造石差值为c的区间数对

代码如下:

#include 
using namespace std;
int n;
long long c;
const int N=2e5+5;
int a[N];
int main()
{
    cin >> n >> c;
    for(int i=0;i> a[i];
    sort(a,a+n);
    long long ans=0;
    for(int i=0,j=0,k=0;i2) ans+=k-j;//计算k和j的差值来求题目所需的值 
    }
    cout <

t4 美丽的区间

算法基础----尺取法(双指针)_第7张图片

算法基础----尺取法(双指针)_第8张图片

思路:依然是双指针的应用,首先用指针i遍历整个区间,用指针j来对区间求和,从第一个数开始依次加到区间和大于等于s,然后计算区间大小的最小值,再然后减去a[i]计算除去第 a[i]个数后的区间和,这样便可以遍历每一种大于等于s的区间和,最后依次比较得到最小值

代码如下:

#include 
using namespace std;
const int N=1e5;
int a[N];
int n,s;
int main()
{
  cin >> n >> s;
  int sum=0;
  int ans=100010;
  for(int i=0;i> a[i];
  for(int i=0,j=0;i=s)
      {
        sum-=a[i];
        ans=min(ans,j-i);
      }
      if(ans==1) break;
  }
  if(ans==100010) cout<<0;
  else cout<

t5 七夕礼物

算法基础----尺取法(双指针)_第9张图片

算法基础----尺取法(双指针)_第10张图片

思路: 首先该题目的意思没有表达清楚就是购买的玩偶必须要是连续的,不然结果完全可以是0。所以依旧是一道求区间和的问题,首先我们可以使用前缀和的方法将每段的区间和算出来,然后将前缀和进行排序,定义双指针,计算前缀和的差值来与t比较求出最小的差值,再写出如下判断条件

1.当re大于t我们就是i++来使re变小,这里还需判断i和j是否相等,如果相等j++

2.当re小于t我们就j++来使re变大

3.当re和t相等时我们直接结束循环即可

代码如下:

#include 
using namespace std;
const int N=1e5+5;
int n,t;
int ans;
int w[N];
int f[N];
int main()
{
  cin >> n >> t;
  ans=t;
  for(int i=1;i<=n;i++){
    cin >> w[i];
    f[i]=f[i-1]+w[i];
  }
  sort(f,f+n+1);
  int i=0,j=1,rs;
  while(j<=n)
  {
    rs=f[j]-f[i];
    ans=min(ans,abs(rs-t));
    if(rs>t)
    {
      i++;
      if(i==j)
      {
        j++;
      }
    }
    else if(rs

你可能感兴趣的:(算法,c++,蓝桥杯)