leetcode 面试题 17.08. 马戏团人塔+面试题 08.13. 堆箱子 最长不下降子序列以及O(nlogn)优化

话不多说直接上题



分析一下,题目要求的是能让所有的箱子竖着堆起来
下面的箱子要比上面的箱子的三维正经的都要大
很明显也就是求一个箱子的摆放序列,使得三维递增
这很明显是一个最长递增子序列问题,那么我们可以
怎么做呢,因为数据量不大,只有3000,直接n^2的dp
就行,先将所有的箱子按照第一维升序排序(很重要)
然后对每一个箱子i,求它作为最下面的时候的最大高度
需要注意的是必须要排序,不然的话此时i作为最下面
不一定是最优的~
应该也可以不排序,只不过这时候要对于每个箱子遍历所有的其他箱子~
于是就有以下的转移方程dp[i] = max(dp[i],dp[j]+hi)对于所有的
三维都小于i的j的箱子


class Solution {
    public int pileBox(int[][] box) {
    	Arrays.sort(box,(int[] a,int[] b)->{
    		return a[0]-b[0];
    	});
        int[] dp = new int[box.length];
        int ans=0;
        for(int i=0; i<box.length; i++){
            dp[i]=box[i][2];
            for(int j=0; j<i; j++){
                if(judge(box[j],box[i]))
                    dp[i]=Math.max(dp[i],dp[j]+box[i][2]);
            }
        }
        for(int i:dp){
            ans=Math.max(ans,i);
        }
        return ans;
    }
   boolean judge(int[] a,int[] b){
        return b[0]>a[0]&&b[1]>a[1]&&b[2]>a[2];
    }
}


很明显,这里要求的是身高体重递增,也是求最长上升子序列的长度
但是不同的是数据量是10^4, 直接n^2的dp的话会在leetcode超时
于是就用到了LIS的优化,优化的过程是,不断的去降低长度为i的
最下面的一个人的体重和身高,这样子下一次进来人的时候,给它
放到最合适它的那一组就可以了,但是要注意的就是,因为这里要求
的是所有的人的体重身高都要增加,所以排序的时候,先按体重升序
然后按照身高降序排列。 于是就有转移方程,假设当前的最长的子序列
长度是maxlen, 则当遇到一个新的人i,由前面的排序过程,可以知道不会
被后面身高相同的人更新,因为它更轻,于是有,if weight[i]>dp[maxlen]
那么dp[maxlen+1]=weight[i],因为它比前面最长的队的人的身高体重都大
else 就找第一个j st.dp[j]>=wight[i].有这个过程可以知道,dp数组是单调非降得
甚至是单调递增得,所以这个过程就是可以用二分查找来做,所以最后得总复杂就是o(nlogn)


import java.util.*;
class Solution {
    public int bestSeqAtIndex(int[] height, int[] weight) {
        //最长递增子序列
        int[] dp = new int[height.length+1]; 
        List<int[]> person = new ArrayList(height.length);
        for(int i=0; i<height.length; i++){
        	person.add(new int[]{height[i],weight[i]});
        }
        person.sort((int[]a,int[]b)->{
        	return a[0]==b[0]?b[1]-a[1]:a[0]-b[0];
        });
        int maxlen=0;
        int pos=0;
        for(int i=0; i<height.length; i++){
        	if(person.get(i)[1]>dp[maxlen])//可以直接更新
        		dp[++maxlen]=person.get(i)[1];
        	else if(person.get(i)[1]<dp[maxlen]){
        		pos=binarySearch(dp,1,maxlen,person.get(i)[1]);
        		dp[pos]=person.get(i)[1];
        	}	
        }
        return maxlen;
    }
    public int binarySearch(int[]dp,int beg,int end,int tatget){
    	int mid=0;
    	while(beg<end){
            //查找的是第一个大于等于他的
            //不能查找第一个大于他的,因为如果查找第一个大于他的
            //可能这个传递过来的是刚好由这个相等传递过来的
            //那么此时这个体重不能更新这一个
    		mid=beg+((end-beg)>>1);
    		if(dp[mid]>=tatget){
    			end=mid;
                //这里是要保留右边的,也就是第一个大于等于的
    		}
    		else{
    			beg=mid+1;
    		}
    	}
    	return end;
    }
}
posted @ 2020-05-04 13:15  CrosseaLL  阅读(305)  评论(0编辑  收藏  举报