Day03—最长上升子序列模型2

Day03—最长上升子序列模型2

896. 最长上升子序列 II

在这里插入图片描述

贪心做法
import java.util.*;

public class Main{
    static Scanner sc=new Scanner(System.in);
    static int[] a=new int[100010];
    static int[] g=new int[100010];
    public static void main(String[] args){
        int n=sc.nextInt();
        
        for(int i=1;i<=n;i++) a[i]=sc.nextInt();
        
        int len=1;
        g[1]=a[1];
        for(int i=1;i<=n;i++){
            //二分查找g[]中第一个大于等于a[i]的元素
            int l=1,r=len;
            while(l<r){
                int mid=(l+r)/2;
                if(g[mid]>=a[i]) r=mid;
                else l=mid+1;
            }
            if(l==len&&a[i]>g[l]) g[++len]=a[i];//若找不到大于等于a[i]的就另开一组
            else g[l]=a[i];//找到直接替换
        }
        
        System.out.println(len);
        
    }
}

897. 最长公共子序列

在这里插入图片描述

import java.util.*;

public class Main{
    static int N=1010;
    static char[] a=new char[N];
    static char[] b=new char[N];
    static int[][] f=new int[N][N];//a从1~i,b从1~j的最长公共子序列集合的长度最大值
    static Scanner sc=new Scanner(System.in);

    public static void main(String[] args){
        int n=sc.nextInt(),m=sc.nextInt();

        String sa=sc.next();
        String sb=sc.next();
        for(int i=1;i<=n;i++) a[i]=sa.charAt(i-1);
        for(int i=1;i<=m;i++) b[i]=sb.charAt(i-1);

        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                f[i][j]=Math.max(f[i-1][j],f[i][j-1]);
                if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1;
            }
        }

        System.out.println(f[n][m]);
    }
}

272. 最长公共上升子序列

在这里插入图片描述

import java.util.*;

public class Main{
    static Scanner sc=new Scanner(System.in);
    static int N=3010;
    static int[] a=new int[N];
    static int[] b=new int[N];
    static int[][] f=new int[N][N];//a的1~i,b的1~j且以b[j]结尾的最长公共上升子序列的最大值
    
    public static void main(String[] args){
        int n=sc.nextInt();
        
        for(int i=1;i<=n;i++) a[i]=sc.nextInt();
        for(int i=1;i<=n;i++) b[i]=sc.nextInt();
        
        
        for(int i=1;i<=n;i++){
            int maxv=1;//maxv表示:当i确定时,每个b[j]<a[i]时的最长公共上升子序的最大值
            for(int j=1;j<=n;j++){
                f[i][j]=f[i-1][j];//不含a[i]的部分
                if(a[i]==b[j]) f[i][j]=Math.max(f[i][j],maxv);
                if(b[j]<a[i]) maxv=Math.max(maxv,f[i-1][j]+1);
            }
        }
        
        int res=0;
        for(int i=1;i<=n;i++) res=Math.max(res,f[n][i]);
        System.out.println(res);
        
        
    }
}

1010. 拦截导弹

在这里插入图片描述

dp+dp做法,第二问利用对偶关系“最少非上升子序列覆盖个数=最长上升子序列长度”
import java.util.*;

public class Main{
    static Scanner sc=new Scanner(System.in);
    static int N=1010;
    static int[] a=new int[N];
    static int[] f=new int[N];
    static int[] g=new int[N];
    
    public static void main(String[] args){
        
        int n=0;
        while(sc.hasNext()){
            a[++n]=sc.nextInt();
        }
        
        for(int i=n;i>=1;i--){
            f[i]=1;
            for(int j=n;j>i;j--){
                if(a[i]>=a[j]) f[i]=Math.max(f[i],f[j]+1);
            }
        }
        
        int res=0;
        for(int i=1;i<=n;i++) res=Math.max(res,f[i]);
        System.out.println(res);
        
        
        for(int i=1;i<=n;i++){
            g[i]=1;
            for(int j=1;j<i;j++){
                if(a[j]<a[i]) g[i]=Math.max(g[i],g[j]+1);
            }
        }
        
        res=0;
        for(int i=1;i<=n;i++) res=Math.max(res,g[i]);
        System.out.println(res);
    }
}
dp+贪心
import java.util.*;

public class Main{
    static Scanner sc=new Scanner(System.in);
    static int N=1010;
    static int[] a=new int[N];
    static int[] f=new int[N];
    static int[] g=new int[N];
    
    public static void main(String[] args){
        
        int n=0;
        while(sc.hasNext()){
            a[++n]=sc.nextInt();
        }
        
        for(int i=n;i>=1;i--){
            f[i]=1;
            for(int j=n;j>i;j--){
                if(a[i]>=a[j]) f[i]=Math.max(f[i],f[j]+1);
            }
        }
        
        int res=0;
        for(int i=1;i<=n;i++) res=Math.max(res,f[i]);
        System.out.println(res);
        
        int len=1;
        g[1]=a[1];
        for(int i=1;i<=n;i++){
            //二分查找第一个大于等于a[i]的
            int l=1,r=len;
            while(l<r){
                int mid=(l+r)/2;
                if(g[mid]>=a[i]) r=mid;
                else l=mid+1;
            }
            if(l==len&&a[i]>g[l]) g[++len]=a[i];//a[i]大于g中所以元素,再加一个
            else g[l]=a[i];//直接替换
        }
        
         System.out.println(len);
    }
}

187. 导弹防御系统

在这里插入图片描述

二分写法
import java.util.*;

public class Main{
    static Scanner sc=new Scanner(System.in);
    static int n;
    static int[] a=new int[60];
    static int[] up=new int[60];
    static int[] down=new int[60];
    static int ans;
    
    public static void dfs(int u, int cu, int cd){//u表示a[]的第几个数,cu表示求上升子序列的贪心序列个数,cu表示求下降子序列的贪心序列个数
       if(cu+cd>=ans) return;
       if(u>n){
           ans=cu+cd;
           return;
       }
       
       int l=0,r=0;
       
       //更新上升子序列贪心数组
       
       if(cu!=0){//上升贪心数组不空时
           l=1;r=cu;//二分查找第一个大于等于a[u]的数
           while(l<r){
                int mid=(l+r)/2;
                if(up[mid]>=a[u]) r=mid;
                else l=mid+1;
            }
       
            if(l==cu&&a[u]>up[l]){//没找到就加一个
                up[++cu]=a[u];
                dfs(u+1,cu,cd);
                up[cu--]=0;
            }else {//找到了
                int t=up[l];
                up[l]=a[u];
                dfs(u+1,cu,cd);
                up[l]=t;
            }
       }else{//为空时特判
           up[++cu]=a[u];
           dfs(u+1,cu,cd);
           up[cu--]=0;
       }
       
       
       //更新下降子序列贪心数组
       if(cd!=0){
            l=1;r=cd;
            while(l<r){
                int mid=(l+r)/2;
                if(down[mid]<=a[u]) r=mid;
                else l=mid+1;
            }
       
            if(l==cd&&a[u]<down[l]){
                down[++cd]=a[u];
                dfs(u+1,cu,cd);
                down[cd--]=0;
            }else {
                int t=down[l];
                down[l]=a[u];
                dfs(u+1,cu,cd);
                down[l]=t;
            }
       }else{
           down[++cd]=a[u];
           dfs(u+1,cu,cd);
           down[cd--]=0;
       }
       
    }
    
    public static void main(String[] args){
        while(true){
            n=sc.nextInt();
            if(n==0) return;
        
            for(int i=1;i<=n;i++) a[i]=sc.nextInt();
        
            ans=n;
            
            dfs(1,0,0);
            
            System.out.println(ans);
        }
        
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值