二分查找法变形之二分答案——如何根据答案去求答案

二分法有朴素二分、特殊二分、二分答案。今天这篇说一下二分答案的具体问题和思路。只有答案有序时才可以这么用哦


image.png

image.png
//#389 暴躁的程序猿
//把暴躁的n个程序员安排在m个工位中,根据它们的编号和工位数求他们之间的最大距离
//员工编号 1 2 8 4 9
//员工编号排序1 2 4 8 9
//距离d = 1 ,工位m = 5
//距离d = 2 ,工位m = 3,1 4 8或 1 4 9两种情况
//距离d = 3 ,工位m = 3
//距离d = 4 ,工位m = 2, 1 8, 1 9, 2 8, 2 9, 4 8, 4 9 六种情况
//距离d = 5 ,工位m = 2, 1 8, 1 9, 2 8, 2 9
//距离d = 6 ,工位m = 2, 1 8, 1 9, 2 8, 2 9
//距离d = 7 ,工位m = 2, 1 8, 1 9
//距离d = 8 ,工位m = 2, 1 9
//距离d = 9... ,工位m = 1,就随便找一个人坐
//距离d可以无限大,工位m为1的时候
//假设距离已知,给一个距离,对应一个工位,随距离增大工位数减小
//距离是从1到  最大编号和最小编号的差
//给你m让你求最大的距离d
//不好求这个问题,但是给一个d能算出分配的工位数m
//可以根据d先求出这个m数,再和题目比较。可能会有一堆d满足。
//d的范围 是从1到  最大编号和最小编号的差 ,怎样在这一堆数里挑一个合适的d呢

//即有一堆满足条件的d,找出最后一个满足条件的d
//最后一个1前面的情况属于func(d) > = m,后面的情况属于func(d) < m
//满足条件看成1,不满足看成0
//抽象成一个1111000的问题,找用二分法找一个d,让它恰巧等于m

//如果m比题目给定的小,说明你的距离偏大,应该动右边的指针
//如果和题目相等,也应该动左边的指针,看看后边是否有满足条件的d,如果有的话选后边那个
//如果比题目给的大,说明你的距离偏小,应该动左边的指针

/*二分查找的两种特殊情况的解决方法
0001111 找第一个1
while (l != r) { //(l<r)
    int mid = (l + r) / 2;
    if (mid == 0) { //
        l = mid + 1;
    } else {
        r = mid;//因为右边的数可能就是第一个1
    }
}

1111000 找最后一个1
while (l != r) {
    int mid = (l + r + 1) / 2;
    //避免为待比较数据个数为偶数(可能刚开始就是偶数,也可能循环到某一次变为偶数,且前一个值满足if条件时。比如后面例子m = 2的 情况) 如1 0出现死循环的情况
    if (mid == 1) { 
        l = mid;
    } else {
        r = mid - 1;
    }
}
*/

#include <iostream>
#include <algorithm>
using namespace std;

int n, m, num[10005], str;

//求一下能安排多少人
int func(int d) {
    int s = 1, last = num[0];
    //无论d是几,都可以在在num[0]放一个人 last记录上个人的位置是哪
    //把每个员工都扫一遍,不需要记录它们的位置
    for (int i = 1; i < n; i++) {
        if (num[i] - last >= d) {
            s++;
            last = num[i];
        }
    }
    return s;
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++)  [
        cin >> num[i];
        tr = max(tr, num[i]);
        //最大的程序员的编号
    ]
    
    sort(num, num + n);
    int l = 1, r = tr;//这里把范围给到了最大编号,可能会多比较几次
    while (l != r) {
        int mid = (l + r + 1) / 2;
        int s = func(mid);
        if (s >= m) { //已知m,算一个距离
            l = mid;
        } else {
            r = mid -1;
        }
    }
    cout << l << endl;
    return 0;
}

为了防止溢出,mid = (l + r) / 2,可替换为mid = l + (r - l) / 2 ,java中可换为mid = (low + high) >>> 1
详细解释见https://leetcode-cn.com/problems/guess-number-higher-or-lower/solution/shi-fen-hao-yong-de-er-fen-cha-zhao-fa-mo-ban-pyth/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351