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);
}
}
}