题目:特殊排序
有 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]
代码与详解:
主观理解的题意大概为:给n个黑盒,每个黑盒只知道其编号,不知道大小,只能通过compare来获知两个黑盒的相对大小,并且大小没有传递性如:a>b,b>c,c可能大于a;现在要按每个黑盒满足左小于右的顺序输出对应的编号
关键点:对于每一个黑盒,都可以通过调用compare来获悉其与其他黑盒的大小关系,要么为大于,要么为小于.根据这个特性,对于任意一个黑盒,我们假设已经有一部分黑盒已经排好了序,这部分已完成的黑盒与当前黑盒的大小关系抽象成折线图,大于表示以上一条折线的终点为起点画一条斜率为负的折线,小于则画斜率为正的折线,最后只要找到这条连续折线上的极大值点,就是我们将要插入的新的黑盒的位置,满足左小右大;
// Forward declaration of compare API.
// bool compare(int a, int b);
// return bool means whether a is less than b.
//时间限制一秒,将复杂度降低到1e7较为合适
class Solution {
public:
vector<int> specialSort(int N) {
vector<int> res;
res.push_back(1);
for(int i=2;i<=N;i++){//每次处理一个
int l=0,r=res.size()-1;
while(l<r){//排好序的区间里的任意一个数对于当前要加入的数要么是大,要么是小,我们的目的是寻找一个左小右大的位置.我们可以对于i设置两个边界值来理解,左端点设置极小值,右端点设置极大值,
int mid=l+r+1>>1;
if(compare(res[mid],i)) l=mid;//如果是res[mid]小于i的话,那么可以找到一个极大值在res[mid]的右方,极限情况下(也就是所有已排好的序列中都有小于i),放在最后面
else r=mid-1;//相反,那么可以找到一个极大值在mid的左方,极限情况况下放在第一个位置
}
res.push_back(i);
for(int j=l+1;j<=res.size()-2;j++){
swap(res[j],res[res.size()-1]);
}
if(r==0&&compare(i,res[r])) swap(res[r],res[r+1]);//经过上面的交换,已经把i移动到r+1的位置
}
return res;
}
};