特殊排序
题目链接
题目描述
有 N个元素,编号 1,2…N,每一对元素之间的大小关系是确定的,关系具有反对称性,但不具有传递性。
注意:不存在两个元素大小相等的情况。
也就是说,元素的大小关系是 N个点与 N×(N−1)2 条有向边构成的任意有向图。
然而,这是一道交互式试题,这些关系不能一次性得知,你必须通过不超过 10000 次提问来获取信息,每次提问只能了解某两个元素之间的关系。
现在请你把这 N 个元素排成一行,使得每个元素都小于右边与它相邻的元素。
你可以通过我们预设的 bool 函数 compare 来获得两个元素之间的大小关系。
例如,编号为 a 和b 的两个元素,如果元素 a 小于元素b,则 compare(a,b) 返回 true,否则返回 false。
将 N 个元素排好序后,把他们的编号以数组的形式输出,如果答案不唯一,则输出任意一个均可。
数据范围
1≤N≤1000
输入样例
[[0, 1, 0], [0, 0, 0], [1, 1, 0]]
输出样例
[3, 1, 2]
题意解读:
题目的意思是有1n号元素需要排序,每两个元素之间有大小关系,但这个关系并没有传递性,类似于拓扑关系,例如如果a<b,b<c,而a不一定小于c。可以通过调用compare(a,b)函数来判断a是否小于b,但最多允许调用10000次。要求调用10000次以内的compare(a,b)函数将1n号元素排好序,保证每两个相邻元素一定满足左边小于右边
无需处理输入输出,只需要补全一个排序函数,排序函数含有一个参数n,返回值是一个vector,表示排好序后的序列。
// Forward declaration of compare API.
// bool compare(int a, int b);
// return bool means whether a is less than b.
class Solution
{
public:
vector<int> specialSort(int N)
{
}
};
分析:
题目的核心在于这些元素大小关系不具有传递性,要求调用少于10000次比较函数来拍好序列。考虑使用插入排序,首先将1号元素插入一个空vectora中,接下来依次将2~n号元素插入a中,每次插入维护a中元素有序。为了快速找到元素应该插入的位置,可以使用二分查找应该插入的位置。
这里为什么可以使用二分呢?a中元素已经排好序,要将i插入a中,假如x是a中元素,进行一次compare(i,x)比较如果有i>x,那么i一定可以插入到x的后方。
不妨进行模拟证明这个结论,假设x是元素a[idx]。首先i尝试插入到x的后一个位置,就要比较i和a[idx+1],如果i<a[idx+1],那么显然i满足了a[idx]<i<a[idx+1],i可以直接插入a[idx]和a[idx+1]之间。否则有a[idx+1]<i,用i比较下一个元素a[idx+2],如果i<a[idx+2],那么显然i满足了a[idx+1]<i<a[idx+2],i可以直接插入a[idx+1]和a[idx+2]之间。如果任然不满足i<a[idx+2]则继续以此类推用i比较下一个元素直到找到一个大于i的元素。如果找到末尾元素任没有大于i的元素,即a[end]<i那么显然i可以插入最后。所以一旦有i>x,那么i一定可以插入到x的后方。i<x,那么i一定可以插入到x的前方。通过这个性质可以每次二分出一个下标mid,判断i可以插入a[mid]的后方还是前方,不断缩小范围最后确定i可以插入的位置。
代码如下:
// Forward declaration of compare API.
// bool compare(int a, int b);
// return bool means whether a is less than b.
class Solution
{
public:
vector<int> specialSort(int N)
{
vector<int>a={1};//起初把1号元素加入
for(int i=2;i<=N;i++)//依次把2~N号元素插入a中
{
//二分查找i号元素应该插入的位置
int l=0,r=a.size()-1;
while(l<r)
{
int mid=(l+r+1)/2;
if(compare(a[mid],i)) l=mid;//i应该插入mid之后
else r=mid-1;//i应该插入mid之前
}
//二分结束后,i应该插入到r的后面。有一种特殊情况是i应该插入到最前面
a.push_back(i);//先将i插入a的末尾
//从后往前依次两两交互,把i换到r的后面
for(int j=a.size()-2;j>r;j--) swap(a[j],a[j+1]);
//处理特殊情况,i应该插入最前面的情况,此时r一定为0
if(compare(a[r+1],a[r])) swap(a[r],a[r+1]);
}
return a;
}
};