首页 > 试题广场 >

搭积木

[编程题]搭积木
  • 热度指数:18755 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 50M,其他语言100M
  • 算法知识视频讲解
小明有一袋子长方形的积木,如果一个积木A的长和宽都不大于另外一个积木B的长和宽,则积木A可以搭在积木B的上面。好奇的小明特别想知道这一袋子积木最多可以搭多少层,你能帮他想想办法吗?
定义每一个长方形的长 L 和宽 W ,袋子里面长方形的个数为 n 。
假如袋子里共有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

输出

4

先排序,然后利用二分查找求长所组成的数组的最长非递减子列的长度,O(NlgN)

import java.util.*;
public class Main {
     public static void main(String[] args) {
         Scanner sc = new Scanner(System.in);
         int N = sc.nextInt();
         Block[] arr = new Block[N];
         for (int i = 0; i < N; i++) {
             arr[i] = new Block(sc.nextInt(), sc.nextInt());
         }

         Arrays.sort(arr, new Comparator() {
             public int compare(Block b1, Block b2) {
                 return b1.W != b2.W ? b1.W - b2.W : b1.L - b2.L;
             }
         });

         int[] spera = new int[N];
         spera[0] = arr[0].L;
         int right = 0;
         int l = 0;
         int r = 0;
         int mid = 0;
         for (int i = 1; i < N; i++) {
             l=0;
             r=right;
             while (l <= r) {
                 mid = l + (r - l) / 2;
                 if (arr[i].L >= spera[mid]) {
                     l = mid + 1;
                 } else {
                     r = mid - 1;
                 }
             }
             right = Math.max(right, l);
             spera[l] = arr[i].L;
         }
        System.out.println(right + 1);
    }
}

class Block {
     public int W;
     public int L;
     public Block(int W,int L){
         this.W=W;
         this.L=L;
    }
}

编辑于 2019-07-20 14:33:25 回复(0)
这题真是神奇,卡极限时间的 ,同样的代码先后提交还有前一次过了后一次就过不了的。
一开始先直接动态规划,超时,后来改进了下,用最长上升子序列的思想,用二分,然后超内存,接着听说用tuple可以降内存,然后***又超时了,最后没办法用了自带的库bisect进行二分查找,就这还有得时候超时。
import bisect 
n = int(input())
data = []
for i in range (n):
    w,l=map(int,input().split(' '))
    data.append((w,l))
data = sorted(data)
###data = [data[i][1] for i in range(len(data))]
binary = []
for i in range(len(data)):
    if not binary:
        binary.append(data[i][1])
    elif binary[-1] <= data[i][1]:
        binary.append(data[i][1])
    else:
        index = bisect.bisect_left(binary,data[i][1])
        binary[index] = data[i][1]
print(len(binary))


编辑于 2020-04-13 01:18:06 回复(1)
JS 答案
// O(nlogn), O(n)
let num = readline()
num = parseInt(num)
let arr = []
while(line = readline()) {
    let [w, l] = line.split(' ')
    arr.push([parseInt(w), parseInt(l)])
}


// 1. sort by width increasing order
arr.sort((a,b) => {
    if (a[0] === b[0]) {
        return a[1] - b[1] // must do this also
    } else {
        return a[0] - b[0]
    }
})

// 2. find length of longest increasing subsequence (not continuous)
let nums = arr.map(i => i[1]) // get lengths
const lengthOfLIS = function(nums) {
    if (nums === null || nums.length === 0) return 0;
    if (nums.length === 1) return 1;
    let len = 0; // final ans
    
    let dp = new Array(nums.length).fill(0);
    for (let i = 0; i < nums.length; i++){
        let pos = binarySearchPosition(dp, nums[i], 0, len);
        dp[pos] = nums[i];
        if (pos === len) len++;
    }

    return len;
};

const binarySearchPosition = (dp, target, start, end) => {
    while (start < end) {
        let mid = Math.floor((start + end)/2);
        if (target >= dp[mid]) start = mid+1;
        else end = mid;
    }
    return end;
}

// print
print(lengthOfLIS(nums))

发表于 2020-04-11 15:07:18 回复(0)
#include<iostream>
(720)#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1000005;
struct NODE
{
    int w;
    int l;
    int id;
}node[maxn];
int f[maxn];
int N;
int lowbit(int x)
{
    return x&(-x);
}

void add(int index, int val)
{
    for (int i = index; i <= N; i += lowbit(i))
    {
        f[i] = max(f[i], val);
    }
}

int query(int index)
{
    int res = 0;
    for (int i = index; i > 0; i -= lowbit(i))
    {
        res = max(res, f[i]);
    }
    return res;
}
bool cmp(const NODE& a, const NODE& b)
{
    if (a.w != b.w) return a.w < b.w;
    else return a.l < b.l;
}
int main()
{

    while (cin>> N)
    {
        for (int i = 1; i <= N; i++)
        {
            cin>> node[i].w>> node[i].l;
            node[i].id = i;
        }
        if (N == 1)
        {
            cout<< 1<< endl;
            continue;
        }
        sort(node+1, node+N+1, cmp);
        memset(f, 0, sizeof(f));
        for (int i = 1; i <= N; i++)
        {
            add(node[i].id, query(node[i].id)+1);
        }
        cout<< query(N)<< endl;
    }
    return 0;
}

发表于 2020-03-20 16:28:41 回复(0)
这个题就是LeetCode354改编的吧
发表于 2020-02-27 23:15:23 回复(1)

先对宽排序。

那么问题就转化成:寻找此时所有长的最长不递减子序列。(注意:与上升还是有点区别)

因为数据量 N 的限制是一百万,所以需要使用 LIS 问题 O(nlogn) 的解法,而不能使用O(n^2)的动态规划解法,会TLE。

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[][] arr = new int[n][2];
        for(int i = 0; i < n; i ++) {
            arr[i][0] = sc.nextInt();
            arr[i][1] = sc.nextInt();
        }

        // 因为 W 都是正数,所以直接做差排序是没问题的。
        Arrays.sort(arr, (e1, e2) -> e1[0] - e2[0]);

        int[] top = new int[n];
        int piles = 0;
        for(int i = 0; i < n; i ++) {
            int target = arr[i][1];

            int l = 0;
            int r = piles;
            while(l < r) {
                int mid = (l + r) >>> 1;
                if(top[mid] > target) {
                    r = mid;
                } else {
                    l = mid + 1;
                }
            }

            if(l == piles) piles ++;
            top[l] = target;
        }

        System.out.println(piles);
    }
}
编辑于 2019-08-06 17:22:18 回复(0)

这个方法运行超时:感觉还可以抢救一下:
import java.awt.Point;
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
Point[] array =new Point [n];
int [] array1=new int [n];
for (int i = 0; i < n; i++)
array[i]= new Point(sc.nextInt(),sc.nextInt());
Arrays.sort(array, new Comparator<Point>() {
@Override public int compare(Point p1, Point p2) {
if( p1.x == p2.x )
return p1.y-p2.y;
return p1.x-p2.x;
}
});
array1[0]=0;
for (int i = 0; i < n; i++)
for (int j = i+1; j < n; j++)
if(array[i].y<=array[j].y)
array1[j]=Math.max(array1[i]+1,array1[j]);
for (int i = 1; i < n; i++)
array1[i]=Math.max(array1[i-1], array1[i]);
System.out.println(array1[n-1]+1);
}
}

发表于 2019-07-03 19:50:38 回复(0)
//对二楼的代码进行了一些精简,占用空间会更小一些,主要是数组a使用一维的就可以了,以及数字输入过程中不需要中间变量P
//顺便加了点注释方便阅读
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int cmp (pair<int, int>a, pair<int, int>b);
int main(){
    //输入数据存入pair,第一个元素为积木宽W,第二个元素为积木长L
    long long a[1000001];
    long long dp[1000001];
    int i,j;
    int n;
    cin>>n;
    int k1,k2;
    vector<pair<int,int> > vec;
    for(i=0;i<n;i++){
        cin>>k1;
        cin>>k2;
        vec.push_back({k1,k2});
    }
    
    //与cmp函数配合实现以pair的第一个元素顺序升序排列
    sort(vec.begin(), vec.end(), cmp);
    for(i=0;i<vec.size();i++){
        a[i]=vec[i].second;
    }
    
    //二分+dp求最长上升子序列
    dp[1]=a[0];
    int len=1;
    for(int i=1;i<n;i++)
    {
        if(a[i]>=dp[len])
            dp[++len]=a[i];
        else
        {
            int j=lower_bound(dp,dp+len,a[i])-dp;
            dp[j]=a[i];
        }
    }
    cout<<len<<endl;
    return 0;
}

//升序排列
int cmp(pair<int, int>a, pair<int, int>b)
{
    return a.first<b.first;
}

发表于 2019-07-03 15:59:43 回复(8)
大致思路:1:先对宽排序 2:长度就等于是求最长非递减子序列的长度。   要注意:排序不要N方,求最长非递减子序列不要n方时间复杂度,也就是不要用dp来做。 
已AC代码
#include<bits/stdc++.h>
using namespace std;
int cmp (pair<int, int>a, pair<int, int>b);
int main(){
    long long a[1000001][2];
    long long d[1000001];
    int i,j;
    int n;
    cin>>n;
    pair<int,int> p;
    int k1,k2;
    vector<pair<int,int> > vec;
    for(i=0;i<n;i++){
        cin>>k1;
        cin>>k2;
        p=make_pair(k1,k2);
        vec.push_back(p);
    }
    
    sort(vec.begin(), vec.end(), cmp);
    for(i=0;i<vec.size();i++){
        a[i][0]=vec[i].first;
        a[i][1]=vec[i].second;
    }
    
    
    d[1]=a[0][1];
    int len=1;
    for(int i=1;i<n;i++)
    {
        if(a[i][1]>=d[len])
            d[++len]=a[i][1];
        else
        {
            int j=lower_bound(d,d+len,a[i][1])-d;
            d[j]=a[i][1];
        }
    }
    cout<<len<<endl;
    return 0;
}

int cmp(pair<int, int>a, pair<int, int>b)
{
    return a.first<b.first;
}

发表于 2019-04-05 22:08:11 回复(1)
我的思路是这样:
    用w(宽)对积木排序,储存在ps数组中;另外创建dpSet集合,保存某l(长)对应的最大层数。
    推算过程是:
        推算到第i个时,检查dpSet中是否有l小于等于ps[i].l的数据,若没有,添加数据(ps[i].l,1(最大层数为1));若有相等,对应数据的最大层数+1;若有小于其的数据,取出该数据储存的层数c,把(ps[i].l,c+1)数据插入到dpSet中。
    每次计算都要检查清理dpSet中l(长)大于它但层数等于它的数据,因为若最大层数相同,后来者应选择l更小的。
    这里用TreeSet压缩查找的时间,之前傻傻地用ArrayList顺序查找,超时了。

public static void main(String[] args) {  Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        Point[] ps = new Point[N];  //这里x是宽,y是长
        for (int i = 0; i  ps[i] = new Point(sc.nextInt(),sc.nextInt());  }
        Arrays.sort(ps, new Comparator() {  @Override  public int compare(Point p1, Point p2) {  //对x(宽)排序  if( p1.x == p2.x )  return p1.y-p2.y;  return p1.x-p2.x;  }  });
        TreeSet dpSet = new TreeSet(new Comparator() {  //与上面不同,这里x是长,y是最大层数,该数据为特定长对应的最大长度  @Override  public int compare(Point o1, Point o2) {  return o1.x - o2.x;  }  }) ;
        for (Point p : ps) {  Point dp = new Point(p.y, 1);  Point dpTmp = dpSet.floor(dp);  //获取长小于等于p的数据  if( dpTmp == null ){  //数据不存在,此时的长最小,最大层数为1  dpSet.add(dp);  }else{  if( dpTmp.x == p.y ){  //若恰有该长的数据,数据对象最大层数+1  dp = dpTmp;  dp.y ++;  }else{  //若无对应数据,将新增点的层数设为小于其的点的层数+1  dp.y = dpTmp.y + 1;  dpSet.add(dp);  }  }  if( (dpTmp = dpSet.higher(dp)) != null && dpTmp.y == dp.y )  dpSet.remove(dpTmp);  //清理其后等于其层数的元素,因为若有后来的方块,只会叠加到此方块下,而不会选择长更大的方块  }
        System.out.println(dpSet.last().y);  }
编辑于 2018-11-14 11:02:39 回复(0)
import java.util.*;

/*
俄罗斯套娃信封问题
首先将积木按照宽度升序排列
比如针对信封[[3,2],[2, 4],[4,3],[5, 6],[6,5]排序后变为
w: 2 -> 3 -> 4 -> 5 -> 6
h: 4 -> 2 -> 3 -> 6 -> 5
问题转化为:
求长度数组h的最长升序子序列的长度
*/
public class Main {
    public static void main(String[] args) {
        // 获取输入
        Scanner scanner = new Scanner(System.in);
        int N = scanner.nextInt();
        if (N == 0) {
            System.out.println(0);
            return;
        }
        int[][] matrix = new int[N][2];
        for (int i = 0; i < N; ++i) {
            matrix[i][0] = scanner.nextInt();
            matrix[i][1] = scanner.nextInt();
        }

        // 按照宽度排序,宽度一样按长度排序
        Arrays.sort(matrix, (int[] r1, int[] r2)->{
            if (r1[0] == r2[0]) {
                return r1[1] - r2[1];
            } else {
                return r1[0] - r2[0];
            }
        });

        // 求长度数组的最长升序子序列的长度
        List<Integer> subOrder = new ArrayList<>();
        // 先将第0个矩形的长度放入
        subOrder.add(matrix[0][1]);

        // 从第1个开始向后遍历
        for (int i = 1; i < N; ++i) {
            // 若大于等于序列的最后一个,添加在序列尾
            if (matrix[i][1] >= subOrder.get(subOrder.size() - 1)) {
                subOrder.add(matrix[i][1]);
            } else {
                // 否则,在序列中找到此值的插入位置,由于序列是有序的,使用二分查找
                int index = Collections.binarySearch(subOrder, matrix[i][1]);
                if (index >= 0) {
                    // 若找到相等的则跳过
                    continue;
                } else {
                    // 否则将该位置的数替换为此数
                    index = - index - 1;
                    subOrder.set(index, matrix[i][1]);
                }
            }
        }

        System.out.println(subOrder.size());
    }
}
编辑于 2020-03-14 01:01:22 回复(3)
为什么我这种先排序在查找的方法,在数据达到10000行的时候会过不去呢?请大神么帮我看看了,谢谢!!!
import java.util.*;
public class Main{
        public static void main(String[] args){
            Scanner input = new Scanner(System.in);
            int N = input.nextInt();
            int[][] a = new int[N][2];
            for (int i = 0;i<N;i++){
                for (int j =0 ;j<2;j++){
                    a[i][j] = input.nextInt();
                }
            }

            //排序:升序,按第一位的升序排列,为了后面只用比较第二列数据做准备
            Arrays.sort(a, new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    if(o1[0]==o2[0])return o1[1]-o2[1];
                    return o1[0]-o2[0];
                }
            });

            //寻找最高的积木层数
            int count = 1;//起始层数为1
            int max = a[0][1];//中间数
            for(int i = 1;i<N;i++){
                if(max<=a[i][1]){
                    max = a[i][1];
                    count++;
                }
            }
            System.out.println(count);
            input.close();
   }
}


发表于 2020-04-17 12:04:01 回复(0)
/*
对长方形的宽w排序,本题化简为对长l求最长上升子序列。
本题只需求最长上升子序列的 长度,可优化到O(nlogn)
*/
#include<bits/stdc++.h>
using namespace std;
#define N 1000000
 
struct rectangle {
    int w = 0, l = 0;
} a[N];
int dp[N];
 
bool cmp(rectangle x, rectangle y){
    return x.w == y.w ? x.l < y.l : x.w < y.w;
}
 
int main()
{
//    freopen("input.txt", "r", stdin);
    int n;
    cin >> n;
    for(int i = 0; i < n; i++) {
        cin >> a[i].w >> a[i].l;
    }
    sort(a, a + n, cmp);
    dp[0] = a[0].l;
    int len = 1;
    for(int i = 1; i < n; i++) {
        if(a[i].l >= dp[len-1]) {
            dp[len++] = a[i].l;
        } else {
            *(upper_bound(dp, dp + len, a[i].l)) = a[i].l;
        }
    }
    cout << len << endl;
    return 0;
}

编辑于 2019-07-05 12:12:17 回复(5)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.TreeSet;

public class Solution3_搭积木 {

    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(bf.readLine());
        //保存积木的宽高的二维数组
        int[][] bricks = new int[n][2];
        String[] strs;
        for (int i = 0; i < n; i++) {
            strs = bf.readLine().split(" ");
            bricks[i][0] = Integer.parseInt(strs[0]);
            bricks[i][1] = Integer.parseInt(strs[1]);
        }
        if (n==1){
            System.out.println(1);
            return;
        }
        //按照宽进行排序,然后求长度的最长上升子序列
        Arrays.sort(bricks, (a, b) -> a[0] - b[0]);
        /**
         * 我们按照宽度从小到大对 bricks 进行了排序
         * dp数组中存储的数积木的长度,它是一个上升的数组,这样才能保证积木的层叠
         */
        int[] dp = new int[n];
        int count = 0;//层数
        for (int i = 0; i < n; i++) {
            if (count == 0 || bricks[i][1] >= dp[count - 1]) {
                //当当前积木的长度 >= dp数组中保存的最大积木长度,那我们就将它加入到 dp 数组中,并且层数加一
                dp[count] = bricks[i][1];
                count++;
            }else {
                /**
                 * 这里解释一下:当我们加入的积木 bricks[i][1],它的长度小于dp中的最大长度
                 * 我们需要在数组dp中找到 <= bricks[i][1] 最接近的值的索引 index,将它替换成现在的长度 bricks[i][1]
                 * 为什么要替换: dp数组中积木的宽度都是小于 bricks[i]的,积木bricks[i]的宽度比dp[index]宽度大,
                 * 而且bricks[i]的长度 >= dp[index],在堆积木情况下,当然是优先选择宽度和长度更大的积木。
                 */
                int index = lowerBound(dp, 0, count, bricks[i][1]);
                dp[index] = bricks[i][1];
            }
        }
        System.out.println(count);
    }
    /**
     * C++中存在的两个方法,用java实现一下
     * ower_bound算法要求在已经按照非递减顺序排序的数组中找到第一个大于等于给定值key的那个数的索引,
     * 其基本实现原理是二分查找
     */
    public static int lowerBound(int[] nums,int l,int r,int target){
        while(l<r){
            int m = (l+r)/2;
            if(nums[m]>=target) r= m;
            else    l = m +1;
        }
        return l;
    }

    /**
     * upper_bound函数要求在按照非递减顺序排好序的数组中找到第一个大于给定值key的那个数索引,
     * 其基本实现原理是二分查找
     */
    public static int upperBound(int []nums ,int l,int r, int target){
        while(l<r){
            int m = (l+r)/2;
            if(nums[m]<=target) l = m+1;
            else    r = m;
        }
        return l;
    }
}

发表于 2019-08-03 15:44:14 回复(7)

/*
哪位大佬帮看一下啊?小数据测试都没问题,当积木数量到了10000之后,就报错了。找了很久不知道哪里出问题了 Q^Q

  • public class DaJiMu {

    public static void main(String[] args) throws IOException {

      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
      int num = Integer.parseInt(bufferedReader.readLine());
      int[][] jimu = new int[num][2];
      for (int i = 0; i < num; i++){
          String[] temp = bufferedReader.readLine().split(" ");
          jimu[i][0] = Integer.parseInt(temp[0]);
          jimu[i][1] = Integer.parseInt(temp[1]);
      }
      Arrays.sort(jimu, new Comparator<int[]>() { @Override public int compare(int[] o1, int[] o2) {
              return o1[0] != o2[0]? o1[0] - o2[0] : o1[1] - o2[1];
          }
      });
      if( num == 1){
          System.out.print(1);
          return;
      }
      int max = 0;
      int[] len = new int[num];
      len[0] = 1;
      //求最长递归子序列
      for (int i = 1; i < num; i++){
          int lastADDIndex = binarySearch(jimu, jimu[i][1], 0, i - 1);
          //若非递减,则选择max(len[i-1]+1, len[差值最小]+1)较大的长度。
          if (jimu[i][1] >= jimu[i-1][1])
              if(lastADDIndex != -1)
                  len[i] = Math.max(len[i-1] + 1, len[lastADDIndex] + 1);
              else
                  len[i] = len[i-1] + 1;
          else{
              if(lastADDIndex != -1){
                  len[i] = len[lastADDIndex] + 1;
              }else
                  len[i] = 1;
          }
          if( max < len[i])
              max = len[i];
      }
      System.out.print(max);

    }

    public static int binarySearch(int[][] arr, int key, int start, int end){

      int max = -1;
      int min = 1000000000;
      while(start <= end){
          int mid = start + (end - start) / 2;
          if(arr[mid][1] <= key) {
              if(min > key - arr[mid][1]) {
                  min = key - arr[mid][1];
                  max = mid;
              }
              start = mid + 1;
          }
          else
              end = mid - 1;
      }
      return max;

    }
    }

编辑于 2019-07-18 14:43:28 回复(4)
import bisect
while True:
    try:
        n = int(input())
        jimu_list = []
        for _ in range(n):
            l, w = map(int, input().split())
            jimu_list.append((l, w))
        # 先按照长 由小到大排序 在此基础上只需要判断宽的最长递增子序列即可
        jimu = list(sorted(jimu_list, key=lambda x: x[0]))
        a = []
        for jimu_info in jimu:
            index = bisect.bisect_right(a, jimu_info[1])
            if index == len(a):
                a.append(jimu_info[1])
            else:
                a[index] = jimu_info[1]
        print(len(a))
        
    except:
        break

发表于 2022-01-20 18:31:13 回复(0)
这份代码报内存超限,请问一下大家有解决的方法吗?还是说python写二分查找这种,就只能内存超限,谢谢大家~

import sys

def solution(num, inputs):
    if num == 0:
        return 0
    inputs = sorted(inputs, key=lambda x:x[0])
    
    dp = [0 for _ in range(num)]
    dp_len = 1
    dp[0] = inputs[0][1]
    for i in range(1, num):
        if inputs[i][1] >= dp[dp_len-1]: 
            dp[dp_len] = inputs[i][1]
            dp_len += 1
        else:    
            index = binarySearch(dp, dp_len, inputs[i][1])
            print(index)
            dp[index] = inputs[i][1]
    return dp_len
    

# 数组中第一个大于或等于key的值
def binarySearch(nums, nums_len, key): 
    l = 0
    h = nums_len - 1
    
    while l <= h:
        mid = l + (h-l) // 2
        if key == nums[mid]:
            return mid
        elif key < nums[mid]:
            h = mid - 1
        else:
            l = mid + 1
    
    return l

n = int(sys.stdin.readline().strip())
li = []
for i in range(n):
    line = sys.stdin.readline().strip()
    lines = list(map(int, line.split()))
    li.append(lines)

print(solution(n, li))

发表于 2021-10-30 00:32:54 回复(0)
最长上升子序列经典题目,方法:动规+二分。先安装宽度w排序,再在长度维度求最长上升子序列,由于n的取值较大,因此需要采用二分法来求。
#include <cstdio>
#include <vector>
#include <climits>
#include <algorithm>
using namespace std;

bool cmp(const pair<int,int>& p1, const pair<int,int>& p2) 
{
    if (p1.first == p2.first)
        return p1.second < p2.second;
    return p1.first < p2.first;
}

int main()
{
    int n;
    scanf("%d", &n);
    vector<pair<int,int>> pairs(n);
    vector<int> d(n+1, INT_MAX);
    for (int i = 0; i < n; ++i)
        scanf("%d%d", &pairs[i].first, &pairs[i].second);
    sort(pairs.begin(), pairs.end(), cmp);
    int p = 0;
    for (int i = 0; i < n; ++i)
    {
        int left = 1, right = p;
        while (left <= right)
        {
            int mid = left+(right-left)/2;
            if (d[mid] <= pairs[i].second)
                left = mid+1;
            else 
                right = mid-1;
        }
        d[left] = pairs[i].second;
        if (left > p) p++;
    }
    printf("%d\n", p);
    
    return 0;
}

发表于 2021-01-09 14:52:54 回复(0)
import java.io.*;
import java.util.*;

public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str;
        while((str = br.readLine()) != null){
            int N = Integer.parseInt(str);
            long[] len = new long[N];
            long[] wid = new long[N];
            long minLen = 0L;
            long minWid = 0L;
            int floors = 0;
            for(int i=0; i < N; i++){
                if((str = br.readLine()) != null){
                    String[] lr = str.trim().split(" ");
                    len[i] = Long.parseLong(lr[0]);
                    wid[i] = Long.parseLong(lr[1]);
                    if(i == 0){
                        minLen = Long.parseLong(lr[0]);
                        minWid = Long.parseLong(lr[1]);
                    }else{
                        if(len[i] <= minLen && wid[i] <= minWid){
                            minLen = len[i];
                            minWid = wid[i];
                        }
                    }
                }
            }
            for(int i=0; i < N; i++){
                if(len[i] >= minLen && wid[i] >= minWid){
                    floors += 1;
                    minLen = len[i];
                    minWid = wid[i];
                }
            }
            System.out.print(floors);
        }
        br.close();
    }
}
万能的大佬路过帮忙看下,测试到42.86%的时候就显示数组越界访问了,感觉自己看的不够仔细,但是一时也找不出问题
发表于 2020-08-24 14:56:35 回复(0)
// dp复杂度有点大,通不过   写一个好理解的二分
#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
struct Node{
    int L;
    int W;
    Node(){}
    Node(int _L, int _W) :L(_L), W(_W){}
};



class Solution {
    public:
     static bool cmp(const Node node1,const Node node2){
         return node1.W == node2.W? node1.L < node2.L : node1.W < node2.W;
     }
     // dp时间复杂度太大
     /*
     int getMax(vector<Node> &arr){
         sort(arr.begin(),arr.end(),cmp);
         vector<int> dp(arr.size(),0);
         int maxdp = 0;
         for(int i=0;i<arr.size();i++){
             dp[i] = 1;
             for(int j=0;j<i;j++){
                 if(arr[j].L <= arr[i].L){
                     dp[i] = max(dp[i],dp[j] + 1);
                 }
             }
             maxdp = max(maxdp,dp[i]);
         }
         return maxdp;
     }
     */
    //为啥别人写的二分好难懂,弄一个好懂的
    int getMax2(vector<Node> &arr){
        sort(arr.begin(),arr.end(),cmp);
        vector<int> lsNum;
        for(int i=0;i<arr.size();i++){
            if(lsNum.size() == 0 || lsNum[lsNum.size()-1] <= arr[i].L){
                lsNum.push_back(arr[i].L);
                continue;
            }
            int low = 0;
            int high = lsNum.size()-1;
            while(low < high){
                int mid = low + (high-low)/2;
                if(lsNum[mid] > arr[i].L){
                    high = mid ;
                }else{
                    low = mid + 1;
                }
            }
            lsNum[low] = arr[i].L;
            
        }
        return lsNum.size();
        
    }
};

int main(){
    int N;
    cin>>N;
    vector<Node> arr;
    int l,w;
    for(int i=0;i<N;i++){
        cin>>l>>w;
        arr.push_back(Node(l,w));
    }
    Solution c1;
    cout<<c1.getMax2(arr)<<endl;
    return 0; 
}

发表于 2020-06-10 17:45:02 回复(0)