算法——马戏团人塔

有个马戏团正在设计叠罗汉的表演节目,一个人要站在另一人的肩膀上。出于实际和美观的考虑,在上面的人要比下面的人矮一点且轻一点。已知马戏团每个人的身高和体重,请编写代码计算叠罗汉最多能叠几个人。
leetcode

纯DP方法

解题思路:首先根据身高将数组顺序排列,然后将身高相同的根据体重顺序排列。这样就是求一个二维的最长上升序列的问题。

利用一个DP数组存储当前元素结尾的最长子序列值,然后从前往后遍历数组,遍历每个元素的时候,再从这个元素开始往前遍历DP数组,寻找身高体重都比自己小的元素,然后取最大值。时间复杂度是N方的。

这样做在leetcode中会超时。

class Solution {
    public int bestSeqAtIndex(int[] height, int[] weight) {
        int n = height.length;
        if(n == 0) return 0;
        List<Integer> man = new ArrayList<>();
        int[] f = new int[n];
        int res = 1;

        for(int i = 0; i < n; i++) man.add(i);

        Collections.sort(man, (b, a) -> height[a] == height[b] ? weight[a] - weight[b] : height[a] - height[b]);

        for(int i = 0; i < n; i++) {
            f[i] = 1;
            for(int j = i - 1; j >= 0; j--) {
                if(height[man.get(j)] > height[man.get(i)] && weight[man.get(j)] > weight[man.get(i)]) {
                    f[i] = Math.max(f[i], f[j] + 1);
                }
            }

            res = Math.max(f[i], res);
        }

        return res;
    }
}

DP + 二分

解题思路:首先将根据将数组根据身高正序排列,然后将身高相同的根据体重逆序排列。这样,就将问题转化为求体重的最长上升序列的问题了。
利用一个DP数组存储当前最长的上升的身高队列,然后也是从后前往后遍历数组,每次遍历到一个元素后,就将这个DP数组进行二分,获取当前元素的最恰当的位置。什么是恰当的位置呢?如果这个元素的值在DP数组的范围中,则替换第一个大于等于它的值,如果这个元素大于DP数组的最大值,则直接添加到最后,同时答案加1。这样是为了保证数组保持递增,同时降低元素的值。

时间复杂度是NlogN 的。不会超时。

  • 为什么身高相同体重需要逆序排列呢?
    当遍历数组的时候,我们当然希望后面的升高越小越好,如果相同的体重,就会出现覆盖的问题,可以让小的覆盖大的,但是不能让大的覆盖小的。
class Solution {
    public int bestSeqAtIndex(int[] height, int[] weight) {
        int len = height.length;
        int[][] person = new int[len][2];
        for (int i = 0; i < len; ++i)
            person[i] = new int[]{height[i], weight[i]};
        Arrays.sort(person, (a, b) -> a[0] == b[0] ? b[1] - a[1] : a[0] - b[0]);


        int [] f = new int [person.length];
        int res = 0;
        for(int [] p : person){
            int l = 0, r = res;
            while(l < r){
                int mid = l + r >> 1;
                if(f[mid] < p[1]) l = mid + 1;
                else r = mid;
            }
            f[r] = p[1];
            if(res == r)  res++;
        }
        return res;
    }
}

原文地址:https://www.cnblogs.com/lippon/p/14117633.html