题目:406. 根据身高重建队列
类型:贪心算法
假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)
表示,其中h
是这个人的身高,k
是排在这个人前面且身高大于或等于h
的人数。 编写一个算法来重建这个队列。
注意:
总人数少于1100人。
示例
输入:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
输出:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
解题思路:
我的思路大概是这样的,即从身高 h 最小的 pair 开始考虑,因为 h 最小,所以根据题意排在他前面的元素应该是只有跟他身高相同或者是空位,则其 k 值就是它在数组中的下标,所以可以从身高的最小值向最大值考虑,依次将 pair 放入容器中,这样的话后面插入的身高值因为永远大于等于之前插入的身高,所以永远不会对之前放入的 pair 产生影响,即前面放入的 pair 放入即确定了位置,之后只需要从头扫描并计数(等于或空位)。
解法一的话是我自己的实现方式,将输入数组按升序排列,插入时也按身高的升序插入,即初始化另一个vector容器来进行结果的保存,并且初始的时候就已经确定好了容器的大小,然后每次都将输入数组中的 pair 复制到输出数组中,判断空位是根据当 pair 的 first 和 second 是否同时为 0 ,但这样的话就需要提前对输入数组中的 (0,0) 进行处理。
解法二是实例代码,它的思路和我的正好相反,即输入数组按降序排列(身高相同时,按 k 值的升序排列),插入时按身高的降序进行插入,即初始时数组为空,后续的元素通过 insert() 进行插入,这样的话就不需要考虑空位的问题了,也就是直接按照当前所操作的一系列相同身高来进行依次插入就可以了,代码也更加的简介明了,很强。
代码:
//解法一:
static bool cmp(pair<int, int> a, pair<int, int> b) {
return a.first < b.first;
}
vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
int len = people.size();
int index = 0, val = 0, start = 0;
vector<pair<int, int>> res(len);
if(!len) return res;
sort(people.begin(), people.end(), cmp);
//略过(0,0)这种情况
while(!people[start].first && !people[start].second) start++;
for(int i = start; i < len; i++){
val = people[i].first;
index = people[i].second;
for(int j = start; j < len; j++){
//如果当前位置为空,且已到达指定位置(前方空位满足条件)则放置元素
if(!index && !res[j].first && !res[j].second){
res[j] = people[i];
break;
//如果当前位置为空或者当前元素大于或等于要放置的元素,则记为一空位
}else if((!res[j].first && !res[j].second) || val == res[j].first)
index--;
}
}
return res;
}
//解法二:
static bool cmp(const pair<int,int>&a,const pair<int,int>&b)
{
if(a.first>b.first) return true;
if(b.first>a.first) return false;
if(a.second<b.second) return true;
return false;
}
vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
sort(people.begin(),people.end(),cmp);
vector<pair<int, int>>ans;
for(vector<pair<int, int>>::iterator iter=people.begin();iter!=people.end();iter++)
{
//利用 insert() 的特性,即插入到指定位置之前
ans.insert(ans.begin()+iter->second,*iter);
}
return ans;
}