五月集训 (第09天) —— 二分查找

Posted 英雄哪里出来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了五月集训 (第09天) —— 二分查找相关的知识,希望对你有一定的参考价值。

文章目录

前言

        此为《英雄算法联盟:算法集训》的内容,具体内容详见:知识星球:英雄算法联盟。加入星球后,即可享用星主 CSDN付费专栏 免费阅读 的权益。
        欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
        希望大家先自己思考,如果实在没有想法,再看下面的算法思路,如果有思路但是写不出来,可以参考朋友圈中其他人的代码,总有一款是适合你的,关注一下他,取其之长,补给之短。
        今天集训的内容是:二分查找
        前两题较为简单,第三题思路稍微转换一下,第四题想了一段时间,是一种预处理的思想。

一、练习题目

题目链接难度
35. 搜索插入位置★☆☆☆☆
704. 二分查找★☆☆☆☆
剑指 Offer 53 - I. 在排序数组中查找数字 I★★☆☆☆
911. 在线选举★★★☆☆

二、算法思路

1、搜索插入位置

        (1)实现一个 int bSearch(int *nums, int n, int target)函数,代表从一个数组中找到大于等于 target 的最小下标;
                (1.1)用一个 ans 来存储这个下标,一开始等于数组的右边界,代表如果不存在大于等于 target 的数,则下标就是这个右边界,即右边界是一个无限大的数;
                (1.2)nums[mid] >= target 表示 mid 是一个满足条件的解,所以我们把 mid 存储下来,继续在 mid 左边尝试找更小的;

int bSearch(int *nums, int n, int target) 
    int l = 0, r = n - 1;
    int ans = n;
    while(l <= r) 
        int mid = (l + r) >> 1;
        if(nums[mid] >= target) 
            ans = mid;
            r = mid - 1;
        else 
            l = mid + 1;
        
    
    return ans;



int searchInsert(int* nums, int numsSize, int target)
    return bSearch(nums, numsSize, target);

2、二分查找

        (1)沿用上一题实现的 bsearch ,如果返回的下标 等于右边界 或者 对应位置不等于 target 则直接返回 -1;否则,返回之前找到的下标。

int bSearch(int *nums, int n, int target) 
    int l = 0, r = n - 1;
    int ans = n;
    while(l <= r) 
        int mid = (l + r) >> 1;
        if(nums[mid] >= target) 
            ans = mid;
            r = mid - 1;
        else 
            l = mid + 1;
        
    
    return ans;



int search(int* nums, int n, int target)
    // >= target 的最小下标
    int index = bSearch(nums, n, target);
    if (index == n) 
        return -1;
    else if(nums[index] != target) 
        return -1;
    
    return index;


3、剑指 Offer 53 - I. 在排序数组中查找数字 I

        (1)还是沿用 bsearch 函数,先找一次大于等于 target 最小下标 index
        (2)如果 index 等于右边界或者对应数组的值不等于 target 直接返回 0;
        (3)否则,继续调用 bsearch 找大于等于 target+1 最小下标 index1,返回结果 index1 - index

// 大于等于 target 的最小下标
int bSearch(int *nums, int n, int target) 
    int l = 0, r = n - 1;
    int ans = n;
    while(l <= r) 
        int mid = (l + r) >> 1;
        if(nums[mid] >= target) 
            ans = mid;
            r = mid - 1;
        else 
            l = mid + 1;
        
    
    return ans;




int search(int* nums, int n, int target)
    int index = bSearch(nums, n, target);
    if(index == n || nums[index] != target) 
        return 0;
    
    return bSearch(nums, n, target + 1) - index;


4、在线选举

        (1)预处理每个时间点的赢家;
        (2)对于每次询问,二分查找小于等于给定时间 t 的最大下标,通过下标去索引赢家;

#define maxn 5001

typedef struct 
    int p[maxn], t[maxn], win[maxn];
    int cnt[maxn];
    int size;
 TopVotedCandidate;


TopVotedCandidate* topVotedCandidateCreate(int* persons, int personsSize, int* times, int timesSize) 
    TopVotedCandidate *obj = (TopVotedCandidate *)malloc(sizeof(TopVotedCandidate));
    memset(obj->cnt, 0, sizeof(obj->cnt));
    int preMaxPerson = -1;
    for(int i = 0; i < personsSize; ++i) 
        obj->p[i] = persons[i];
        obj->t[i] = times[i];
        ++obj->cnt[  obj->p[i] ];
        if(preMaxPerson == -1 || obj->cnt[ obj->p[i] ] >= obj->cnt[ preMaxPerson ] ) 
            preMaxPerson = obj->p[i];
        
        obj->win[i] = preMaxPerson;
    
    obj->size = personsSize;
    return obj;


int topVotedCandidateQ(TopVotedCandidate* obj, int t) 
    int l = 0, r = obj->size - 1;
    int ans = -1;
    while(l <= r) 
        int mid = (l + r) >> 1;
        if(obj->t[mid] <= t) 
            ans = mid;
            l = mid + 1;
        else 
            r = mid - 1;
        
    
    return obj->win[ans];


void topVotedCandidateFree(TopVotedCandidate* obj) 
    free(obj);

以上是关于五月集训 (第09天) —— 二分查找的主要内容,如果未能解决你的问题,请参考以下文章

六月集训(第09天) —— 二分查找

七月集训(第09天) —— 二分查找

五月集训(第26天) —— 并查集

五月集训(第18天) —— 树

五月集训(第14天) —— 栈

五月集训(第24天) —— 线段树