蓝桥杯上岸必背!!!(第二期)

第二期:双指针(基础算法) ✨

蓝桥杯4月8号就要开始了~

大家好 我是寸铁 ✨

蓝桥杯每日一题系列持续更新中,小伙伴们快上车!冲冲冲💘

预祝大家蓝桥杯都能上岸👊

冲刺蓝桥杯省一吧必背模板来啦~

往期回顾

蓝桥杯上岸必背!!!(第一期)

考点秘籍

蓝桥杯省一你一定不能错过的模板大全(第一期)

蓝桥杯每日一题 最少刷题数

蓝桥杯每日一题 求阶乘

蓝桥杯 Java 省赛 B 组(初赛)填空题

Java快读快写

java常用数组拷贝

常用Java竞赛基础技能总结

双指针和二分的覆盖面广!!!

且较为常用!!!

下面让我们一起来背模板~~~

双指针算法

一般分为两大类:

(1)两个序列中移动i、j指针

在两个序列中分别移动i、j指针
当两个指针均移动到终点时,双指针算法结束
常见的是归并排序的合并过程。

(2)一个序列中移动i、j指针

固定一个指针,然后去移动另一个指针
常见:快速排序。

模板结构:

for(int i=0,j=0;i<n;i++){
    while(j<i&&check(i,j))j++;
    
    //每道题目的具体逻辑
}

核心思想:将暴力算法优化到O(n)

挖掘某些性质,减少枚举的次数。
直接暴力两重循环:O(n^2)

for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
        //
    }
}

双指针优化:

O(2*n)=O(n)

for(int i=0,j=0;i<=n;i++){
    while(j<i&&check(i,j))j++;
}

双指针算法是一种思想,无固定的模板,这里以模板题为例

模板题

分析

两个指针i,j指针j距离指针i最靠左的距离为多少
右指针往前移动,左指针维持不动或者往前移动,不会往后移动
可以得出i、j的移动具有单调性
因此可以用双指针算法去移动两个指针
while()移动j指针,移动直至j~i这段区间都无重复元素为止。
s[a[i]]=1

注意

while():多次循环
if()判断语句:执行一次

最长连续不重复子序列

//对一段序列用两个指针实现不同位置的同步移动
import java.util.*;
public class Main{
    static int N=100010;;
    static int a[]=new int [N];
    //输入数组
    static int s[]=new int [N];
    //统计序列中每个a[i]出现的次数
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int res=0;
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int i=0,j=0;i<n;i++){
            s[a[i]]++;
            //对于i~j的这段不重复数的区间
            //如果是出现重复数一定是出现在i的位置
            //即s[a[i]]>1
            
            //注意是While()循环,执行多次判断,移动j指针。
            //写成if的话,是不会一直移动j指针
            while(j<=i&&s[a[i]]>1){
                s[a[j]]--;
                //从j~i这段区间一直除,直至s[a[i]]的个数为1
                j++;
                //每除一次,j往i的方向移动一次
                //除到s[a[i]]=1时,j不再移动
                //此时j~i这段区间的数均不重复
            }
            res=Math.max(res,i-j+1);
            //更新到每个i的最大不连续区间长度
            //可以理解为j最左离i的距离是多少
        }
        System.out.println(res);
    }
}

模板背完后,做做例题吧 👊

例题:AcWing 800. 数组元素的目标和

做法如下:

双指针

//由于两个都是升序数组
//存在单调性
//我们拿上面最小的元素去和下面最大的元素进行匹配
//因为最小的元素都匹配不了,则该序列中后面的元素必定匹配不了。
//如果说最小的元素匹配后的值比x要大,则移动j指针
//j指针移动至和值小于等于x时停止,移动i后面的数能否匹配。
//匹配过程出现和值>=x时,则继续移动j指针。
import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int[N];
    static int b[]=new int[N];
    public static void main(String []args)
    {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int x=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int i=0;i<m;i++)b[i]=sc.nextInt();
        for(int i=0,j=m-1;i<n;i++){
           while(j>=0&&a[i]+b[j]>x)j--;
            if(a[i]+b[j]==x){
                System.out.println(i+" "+j);
                return;
            }
    }
}
}

二分

import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int [N];
    static int b[]=new int [N];
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int x=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int j=0;j<m;j++)b[j]=sc.nextInt();
        for(int i=0;i<n;i++){
            int t=x-a[i];
            //看b序列中是否能二分出答案
            
            //枚举n次
            //看能否在b序列中找到
            int l=0,r=m-1;
            //确定左右边界
           while(l<=r){
               //这里需要枚举b序列的每一个位置
               //l<=r
               
               //开始二分
               int mid=l+r>>1;
               //二分的中间点
               if(b[mid]==t){//二分的答案
            
               System.out.println(i+" "+mid);
               //a序列的位置+" "+b序列的位置
                return;
                //唯一解,找到就返回
               }
               else if(b[mid]>t)r=mid-1;
               //mid这个值比t要大
               //b[mid]已经被比较过,所以r=mid-1;
               else l=mid+1;
               //mid这个值比t要小
               //b[mid]已经被比较过,所以l=mid+1;
           } 
        }
    }
}

AcWing 2816. 判断子序列

Accode

import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int[N];
    static int b[]=new int[N];
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int j=0;j<m;j++)b[j]=sc.nextInt();
        //指针的定义不一定需要for循环
        //可以单独定义两个指针然后while循环
        int i=0;
        int j=0;
        while(i<n&&j<m){
            //在两个序列的范围内
            if(a[i]==b[j])i++;
            //找到匹配的情况则i往下走,看i是否可以匹配
            j++;
            //j一直++,往前移动,看是否能够匹配
        }
        //最后一个i=n-1,n-1匹配上j后,则i++后等于n
        //如果刚好i等于n则说明a序列刚好与b序列匹配,输出Yes。
        //这也是一个小技巧
        if(i==n)System.out.println("Yes");
        else System.out.println("No");
    }
}

Java竞赛常用

https://www.myblog.link/2016/11/14/Note-of-java/
👍👍👍👍👍👍
看到这里,不妨点个关注 💖

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寸 铁

感谢您的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值