搭積木
小明有一袋子長方形的積木,如果一個積木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
原題:
題目鏈接
我的代碼:
- 超時了
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);
}
}
- 問了打 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;
}
- 最終的代碼
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 的那個數,可以使用“二分法”