题目描述
有个马戏团正在设计叠罗汉的表演节目,一个人要站在另一人的肩膀上。出于实际和美观的考虑,在上面的人要比下面的人矮一点且轻一点。已知马戏团每个人的身高和体重,请编写代码计算叠罗汉最多能叠几个人。
示例:
输入:height = [65,70,56,75,60,68] weight = [100,150,90,190,95,110]
输出:6
解释:从上往下数,叠罗汉最多能叠 6 层:(56,90), (60,95), (65,100), (68,110), (70,150), (75,190)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/circus-tower-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
- 这里有一个问题,就是上一层要比下一层矮一点瘦一点,也就是说在身高相同的情况下,只能选一个最瘦的
- 这道题就是求一个最长上升子序列,使得第i个比i-1个的体重小一点,身高矮一点。
- 最长上升子序列有两种求法,动态规划和二分法
- 动态规划的dp[i]指的是以数组中第i个元素结尾的最长上升序列的长度
- 二分法的d[i]是单调递增数组,d[i]代表的是长度为i的上升子序列的最后一个元素的值
- 首先应该对身高排序,如果升高一致,对体重进行倒序排序,这里参考了题解,人家通过构建二维数组,使用库函数巧妙地解决了这个问题
- 对体重采用倒序排列,是为了在后续采用贪心+二分法,解决最长子串问题时,在身高相同的情况下,尽可能选择体重轻的那一个人。
- 总结:这道题巩固了贪心+二分,促使我看了binarySearch的源码,为怎么实现多条件排序提供了套路
代码
class Solution {
public int bestSeqAtIndex(int[] height, int[] weight) {
if(height == null || weight == null || height.length == 0 || weight.length == 0 || weight.length != height.length) return 0;
int[][] person = new int[height.length][2];
for(int i = 0; i < height.length; i++){
person[i] = new int[]{
height[i], weight[i]};
}
Arrays.sort(person, (o1, o2) -> o1[0] == o2[0] ? o2[1] - o1[1] : o1[0] - o2[0]);
int[] d = new int[height.length];
d[0] = person[0][1];
int len = 1;
for(int i = 1; i < height.length; i++){
int index = Arrays.binarySearch(d, 0, len, person[i][1]);
if(index < 0){
index = -(index + 1);
}
d[index] = person[i][1];
if(index == len) ++len;
}
return len;
}
}