传送门
题目描述
有个马戏团正在设计叠罗汉的表演节目,一个人要站在另一人的肩膀上。出于实际和美观的考虑,在上面的人要比下面的人矮一点且轻一点。已知马戏团每个人的身高和体重,请编写代码计算叠罗汉最多能叠几个人。
示例:
输入: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)
提示:
height.length == weight.length <= 10000
题解思路
题目要求人塔中上面一人的体重和身高都要分别小于其下面那人的体重和身高,注意:此处不包括等于;
因此,我们可以对给出的体重和身高数据进行排序,方面后面的建塔操作,我们不难发现:建造人塔对人数并没有严格的要求,只要体重数据和身高数据合适,任何数目都可以建造成一个人塔(0人除外)
初始数据如下:
第一步
优先按身高从小到大排序,当身高相同时按体重从大到小排序,为什们体重要从大到小排序呢?我们将在下面的讨论中得出答案;
第二步(对降序的情况讨论)
在身高已经排好序的情况下,我们只需考虑体重的大小,接下来的问题与求最长上升子序列的问题十分相似,具体流程如下:
如果当前的体重大于dp数组中最大体重(即末尾元素)时,直接在dp数组中尾插一个新元素
当遇到当前体重(100)小于dp数组中最大元素(110)时,使用二分查找的方法找出dp数组中第一个大于或等于当前体重的元素下标,并将该位置的数值更新为当前体重值(100)
结束!返回当前dp数组的大小,即是建造人塔的最大人数;
讨论体重升序的情况
加入当身高一致时,体重按升序排列,则会如下情况:
由于当前体重(130)大于dp数组中最大元素(124),dp数组会尾插元素(130),这显然是一种错误的操作,因为此时他们的身高相同了,而题目要求上面人的身高和体重都要分别小于下面人的身高和体重
利用体重降序的方式可以巧妙地避免这个问题!
代码实现
class Solution {
public:
int bestSeqAtIndex(vector<int>& height, vector<int>& weight) {
int n = height.size();
if(n <= 1)
return n;
vector<pair<int,int>>Sorted(n);
for(int i = 0; i < n; i++)
{
Sorted[i].first = height[i];
Sorted[i].second = weight[i];
}
sort(Sorted.begin(),Sorted.end(),[&](auto a,auto b)
{
if(a.first < b.first)
return true;
else if(a.first == b.first)
return a.second > b.second;
else
return false;
});
//上面实现了优先按身高从小到大排序,其次按体重从大到小排序
vector<int>dp;
dp.push_back(Sorted[0].second);
for(int i = 0; i < n; i++)
{
if(Sorted[i].second > dp.back())
dp.push_back(Sorted[i].second);
else
{
//找出dp数组中第一个大于或等于当前体重的元素下标
auto pos = lower_bound(dp.begin(),dp.end(),Sorted[i].second);
*pos = Sorted[i].second;//将该位置的数值缩小(贪心)
}
}
return dp.size();
}
};