二分算法例题——特殊排序

题目:特殊排序

有 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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

切勿踌躇不前

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值