最长上升子序列变题(搭积木)

搭积木
小明有一袋子长方形的积木,如果一个积木A的长和宽都不大于另外一个积木B的长和宽,则积木A可以搭在积木B的上面。好奇的小明特别想知道这一袋子积木最多可以搭多少层,你能帮他想想办法吗?
定义每一个长方形的长L和宽W都为正整数,并且1 <= W <= L <= INT_MAX, 袋子里面长方形的个数为N, 并且 1 <= N <= 1000000.
假如袋子里共有5个积木分别为 (2, 2), (2, 4), (3, 3), (2, 5), (4, 5), 则不难判断这些积木最多可以搭成4层, 因为(2, 2) < (2, 4) < (2, 5) < (4, 5)。
输入描述:

第一行为积木的总个数 N

之后一共有N行,分别对应于每一个积木的宽W和长L

输出描述:

输出总共可以搭的层数

示例1
输入
复制

5
2 2
2 4
3 3
2 5
4 5

原题:
题目链接

我的代码:

  1. 超时了
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class Main {
    static class Block implements Comparable<Block>{
        long x;
        long y;
        public Block(long x,long y) {
            this.x = x;this.y = y;

        }
        @Override
        public int compareTo(Block o) {
            int dx = (int) (this.x - o.x);
            if(dx==0) {
                //判断dy
                return (int) (this.y - o.y);
            }else{
                return dx;
            }
        }

    }
    public static void main(String[] args) throws IOException {
        BufferedReader bf =
                new BufferedReader(new InputStreamReader(System.in));
        int n= Integer.parseInt(bf.readLine());
        Block[] blocks = new Block[n];
        int[]dp =new int[n+1];
        for(int i=0;i<n;++i) {
            String[]line = bf.readLine().split(" ");
            blocks[i] = new Block(Integer.parseInt(line[0]),Integer.parseInt(line[1]));
            dp[i] = 1;
        }
        bf.close();
        Arrays.sort(blocks);
        int res = 1;
        for(int i=1;i<blocks.length;++i) {
             for(int j = 0;j<i;++j) {
                 if(blocks[i].y>=blocks[j].y) {
                     dp[i] = Math.max(dp[i],dp[j]+1);
                 }
             }
             res = Math.max(dp[i],res);
        }
        System.out.println(res);

    }





}
  1. 问了打 ACM同学的代码

#include <bits/stdc++.h>
#define MAX_INT  ((unsigned)(-1)>>1)
#define MIN_INT  (~MAX_INT)
#define db printf("where!\n");
#define pb push_back
using namespace std;
#define ll long long
ll gcd(ll x,ll y){return y ? gcd(y,x%y) : x;}
template<class T>inline void read(T &res){
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
struct node
{
    int a,b;
}d[1000005];
bool cmp(node a,node b)
{
    if(a.a==b.a) return a.b<b.b;
    return a.a<b.a;
}
int dp[1000005];
int main()
{
    int n;read(n);
    for(int i=1;i<=n;i++){
        int a1,a2;
        read(a1),read(a2);
        d[i].a=a1,d[i].b=a2;
    }
    sort(d+1,d+1+n,cmp);
    int len=0;
    for(int i=1;i<=n;i++){
        if(d[i].b>=dp[len]){
            dp[++len]=d[i].b;
        }
        else{
            int l=1,r=len;
            while(l<r){
                int mid=(l+r)/2;
                if(dp[mid]>d[i].b) r=mid;
                else l=mid+1;
            }
            dp[l]=d[i].b;
        }
    }
    //for(int i=1;i<=n;i++) cout<<dp[i]<<" ";
    cout<<len<<endl;

 return 0;
}
  1. 最终的代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class Main {
    static class Block implements Comparable<Block>{
        int x;
        int y;
        public Block(int x,int y) {
            this.x = x;this.y = y;

        }
        @Override
        public int compareTo(Block o) {
            int dx = (int) (this.x - o.x);
            if(dx==0) {
                //判断dy
                return (int) (this.y - o.y);
            }else{
                return dx;
            }
        }

    }
    public static void main(String[] args) throws IOException {
        BufferedReader bf =
                new BufferedReader(new InputStreamReader(System.in));
        int n= Integer.parseInt(bf.readLine());
        Block[] blocks = new Block[n];
        int[]dp =new int[n+1];
        for(int i=0;i<n;++i) {
            String[]line = bf.readLine().split(" ");
            blocks[i] = new Block(Integer.parseInt(line[0]),Integer.parseInt(line[1]));

        }
        bf.close();
        Arrays.sort(blocks);
        int p = 0;
        int[] tail = new int[n+1];
        for(int i=0;i<n;++i) {
            if(tail[p]<=blocks[i].y) {
                tail[++p] = blocks[i].y;
            }else{
                int l = 0,r = p;
                int find = blocks[i].y;
                while(l<r) {
                    int mid = (l+r)>>1;
                    if(tail[mid]<find) {
                        // mid -> find
                        l = mid+1;
                    }else{
                        //tai[mid]> find   find -> mid
                        r = mid;
                    }
                }
                tail[l] = find;
            }

        }
        System.out.println(p);

    }





}

思路: 这个题目的原题是 求最长上升子序列
也就是 leetCode的第300题

思路1 是不同解法,时间复杂度是 o(N^2)
可以通过 二分法 优化为 o(NlogN)

思路:贪心算法(二分法)

思路:每一次来一个新的数 num,在 tail 数组(tail 数组的定义在下面的示意图中有)中找大于等于 num 的那个数,试图让它变小,以致于新来的数有更多的可能性接在它后面,成为一个更长的“上升子序列”,这是“贪心算法”的思想。

在 tail 数组中找大于等于 num 的那个数,可以使用“二分法”
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值