最長上升子序列變題(搭積木)

搭積木
小明有一袋子長方形的積木,如果一個積木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 的那個數,可以使用“二分法”
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章