【剑指Offer】--->详解二分查找相关练习

这篇具有很好参考价值的文章主要介绍了【剑指Offer】--->详解二分查找相关练习。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

没有人会为你踏雾而来,喜欢的风景要自己去看。

【剑指Offer】--->详解二分查找相关练习

二分查找相信大家都应该不陌生,本次博主为大家带来的是一些有关二分查找变形的有关题目(来自剑指offer),相信认真读完了后对初学者会有一定的帮助(我也是初学者,各位大佬不要喷我)

目录

​1 数字在有序数组中出现的次数​

 2 旋转数组的最小数字​

3 寻找峰值​

 4 二维数组的查找​


在此之前,我们先来做一个简单的练习温习一下最简单的二分查找:

【剑指Offer】--->详解二分查找相关练习最简单的二分查找【剑指Offer】--->详解二分查找相关练习

这个题我相信大家都会,就不多讲了,具体代码:

int search(int* nums,int numlen,int target)
{
    if(numlen==0)
        return -1;
    if(numlen==1)
    {
        if(target==nums[0])
            return 0;
        else
            return -1;
    }
    int left=0;
    int right=numlen-1;
    int mid=0;
    while(left<=right)
    {
         mid=(left+right)/2;
        if(target>nums[mid])
            left=mid+1;
       else if(target<nums[mid])
            right=mid-1;
        else
            return mid;
    }
    return -1;
}

接下来就开始我们的正题了:

​1 数字在有序数组中出现的次数​

 题目描述:

给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数

数据范围:0≤n≤1000,0≤k≤1000 ,数组中每个元素的值满足 0≤val≤1000
要求:空间复杂度 O(1),时间复杂度 O(logn)

示例1:

输入:[1,2,3,3,3,3,4,5],3

返回值:4

 示例2:

输入:[1,3,4,5],6

返回值:0

【剑指Offer】--->详解二分查找相关练习解题思路:【剑指Offer】--->详解二分查找相关练习

根据题目要求遍历数组肯定是行不通的,那么我们就要考虑用二分查找这种方法,假设我们给定一个数组[1,2,3,3,3,3,4,5],要求3出现的次数,如果我们能找到比3恰好的位置,比3恰好的位置,两者相减就是要找到的数出现的次数。所以我们不妨将k-0.5的位置和k+0.5的位置找出来,上面k-0.5的位置为2,k+0.5的位置为6,相减恰好是k出现的次数4.

动图展示:

【剑指Offer】--->详解二分查找相关练习

 具体代码:

int binaSerch(int*data,int dataLen,double k)
 {
     int left=0;
     int right=dataLen-1;

     while(left<=right)
     {
         int mid=left+((right-left)>>1);
         if(data[mid]>k)
         {
             right=mid-1;
         }
         else
         {
             left=mid+1;
         }
         
     }
     return left;
 }
int GetNumberOfK(int* data, int dataLen, int k ) {
    
    return binaSerch(data, dataLen, k+0.5) - binaSerch(data, dataLen, k-0.5);
}

【剑指Offer】--->详解二分查找相关练习注意事项:【剑指Offer】--->详解二分查找相关练习

  1.  分装的二分查找函数中的k要用浮点型
  2. 由于data[mid]不可能等于k,所以不需要判断他们相等的情况

 2 旋转数组的最小数字

 题目描述:

有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

数据范围:1≤n≤10000,数组中任意元素的值: 0≤val≤100000

要求:空间复杂度:O(1),时间复杂度:O(logn)

示例1:

输入:[3,4,5,1,2]

返回值:1

 示例2:

输入:[3,100,200,3]

返回值:3

【剑指Offer】--->详解二分查找相关练习解题思路: 【剑指Offer】--->详解二分查找相关练习

由于数组是升序,我们可以知道当数组还没有旋转的时候最小值一定在最左边,旋转了后除了还未旋转外最左边的值不可能小于最右边的值,所以当最左边的数如果小于最右边的数时就可以直接返回最左边的数·(大家可以带一些值去试试)。

我们可以认为旋转后将原数组分成了两个有序的数组,现在关键是如何确定最小值在哪个区间,所以我们每次可以用中间值作比较来确定最小值的区间。

我们假定给出数组[1,2,3,4,5],旋转后的情况不外乎是:

[2,3,4,5,1]

[3,4,5,1,2]

[4,5,1,2,3]

[5,1,2,3,4]

通过上面我们发现:若是区间中点值大于区间右界值,则最小的数字一定在中点右边。

若是区间中点值小于区间右界值,则最小的数字一定在中点左边(包括中点)。

但是上面没有区间中点值等于区间右界值的情况,若是区间中点值等于区间右界值,则是不容易分辨最小数字在哪半个区间,比如[1,1,1,0,1],应该逐个缩减右界。

 动图展示:

【剑指Offer】--->详解二分查找相关练习

 具体代码:

int minNumberInRotateArray(int* rotateArray, int rotateArrayLen ) {
    // write code here
    int left=0;
    int right=rotateArrayLen-1;
    if(rotateArray[left]<rotateArray[right])
    {
        return rotateArray[left];
    }
    while(left<=right)
    {
        int mid=left+((right-left)>>1);
        if(rotateArray[mid] > rotateArray[right])
        {
            left=mid+1;
        }
        else if(rotateArray[mid] < rotateArray[right])
        {
            right=mid;
        }
        else
        {
            right--;
        }
    }
    return rotateArray[left];
}

 【剑指Offer】--->详解二分查找相关练习注意事项:【剑指Offer】--->详解二分查找相关练习

  1.  可以先判断最左边的值与最右边值的大小,如果最左边的数小于最右边的数时就可以直接返回最左边的数
  2. 区间中点值等于区间右界值的情况,应该逐个缩减右界

3 寻找峰值

题目描述;

给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。

1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于

2.假设 nums[-1] = nums[n] = −∞

3.对于所有有效的 i 都有 nums[i] != nums[i + 1]

4.你可以使用O(logN)的时间复杂度实现此问题吗?

数据范围:

1≤nums.length≤2×10^5

−2^31<=nums[i]<=2^31−1

如输入[2,4,1,2,7,8,4]时,会形成两个山峰,一个是索引为1,峰值为4的山峰,另一个是索引为5,峰值为8的山峰,如下图所示:

【剑指Offer】--->详解二分查找相关练习

 示例1:

输入:[2,4,1,2,7,8,4]

返回值:1

说明:4和8都是峰值元素,返回4的索引1或者8的索引5都可以

示例2:

输入:[1,2,3,1]

返回值:2

说明:3 是峰值元素,返回其索引 2

【剑指Offer】--->详解二分查找相关练习解题思路:【剑指Offer】--->详解二分查找相关练习

题目要求时间复杂度为O(logN),所以暴力求解肯定不行,因为题目将数组边界看成最小值,而我们只需要找到其中一个波峰,因此只要不断地往高处走,一定会有波峰。那我们可以每次找一个标杆元素,将数组分成两个区间,每次就较高的一边走,因此也可以用分治来解决,而标杆元素可以选择区间中点。

如果中间值大于它右边的值:我们不妨举个例子[x,x,x,5,4,x,x],其中x为任意值,我们可以带入一些值进去发现右边是不一定有坡峰的,如[x,x,x,5,4,5,4](有坡峰)[x,x,x,5,4,3,2](无坡峰),这也好解释由于右边是往下走的所以不能够确定峰值。但是左边一定是会有峰值的,同理我们可以来分析如果左边值是逐渐递减的如[9,8,6,5,4,x,x],我们可以知道9就是峰值,如果索引为2的值只要小于5那么5就是峰值,如果索引为2的值大于5那么索引为1的值如果小于索引为2的话索引为2就是峰值,否则索引为0的值如果大于索引为1的话索引为0就是峰值,否则索引为1的就是峰值。(这里关系比较复杂,大家可以自己去推推)。

同理如果中间值小于右边的元素,说明此时往右是向上,向上一定能有波峰。

 动图展示:

【剑指Offer】--->详解二分查找相关练习

 具体代码:

int findPeakElement(int* nums, int numsLen ) {
    // write code here
    int left=0;
    int right=numsLen-1;
    while(left<right)
    {
        int mid=(left+right)/2;
        if(nums[mid]>nums[mid+1])
        {
            right=mid;
        }
        else
        {
            left=mid+1;
        }
    }
    return left;
}

【剑指Offer】--->详解二分查找相关练习注意事项:【剑指Offer】--->详解二分查找相关练习

  1. while循环中没有加=,加了=后会出错
  2. 往高处走一定有坡峰,当nums[mid]>nums[mid+1]时,中间值更大,所以向左缩短区间,nums[mid]<nums[mid+1]时,中间值右边更大,所以向右缩短区间。

 4 二维数组的查找

题目描述:

在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

[

[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]

]

给定 target = 7,返回 true。

给定 target = 3,返回 false。

数据范围:矩阵的长宽满足 0≤n,m≤5000, 矩阵中的值满足 0≤val≤10^9
进阶:空间复杂度 O(1),时间复杂度 O(n+m)

 示例1:

输入:7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]

返回值:true

说明:存在7,返回true

示例2:

输入:1,[[2]]

返回值:false

说明:不存在1,返回false

示例3:

输入:3,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]

返回值:false

说明:不存在3,返回false

 【剑指Offer】--->详解二分查找相关练习解题思路:【剑指Offer】--->详解二分查找相关练习

 这道题常规遍历肯定是行不通的,我们可以考虑用二分查找的思维来做题,二分查找就是不断的缩小区间直至我们找到我们想要找到的数据,我们通过题目描述不难发现这个二维数组其实就是一个杨氏矩阵(行从左到右依次递增,列从上到下依次递增),我们可以紧紧抓住这个条件,首先将数据定位到最右上边的元素(左下也行),如果要查找的元素比右上边的元素还大,那我们就可以排除这一行了,如果要查找的元素比右上边的元素还小,那么就可以排除这一列,然后迭代的走下去,注意控制循环结束的条件。

 动图展示:

【剑指Offer】--->详解二分查找相关练习

 具体代码:

bool Find(int target, int** array, int arrayRowLen, int* arrayColLen ) {
    // write code here
    int row=0;
    int col=*arrayColLen-1;

    while(row < arrayRowLen  && col >= 0)
    {
        if(array[row][col] > target)
        {
            col--;
        }
        else if(array[row][col] < target)
        {
            row++;
        }
        else 
        {
            return true;
        }
    }
    return false;
}

【剑指Offer】--->详解二分查找相关练习注意事项:【剑指Offer】--->详解二分查找相关练习

 循环结束的条件要控制好。


【剑指Offer】--->详解二分查找相关练习结语【剑指Offer】--->详解二分查找相关练习

与二分查找相关的题目还有很多,但是终归这些题都是在如何利用已知条件来转换成我们所熟悉的二分方法,如果觉得博主的文章对你有帮助的话可不可以3连支持一下,后面博主还会持续更新剑指offer上的有关题目。

【剑指Offer】--->详解二分查找相关练习文章来源地址https://www.toymoban.com/news/detail-403857.html

到了这里,关于【剑指Offer】--->详解二分查找相关练习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 剑指offer -- 二维数组中的查找

    二维数组中的查找_牛客题霸_牛客网 (nowcoder.com) 暴力查找法: 是一种简单直接的解决方法,可以用于在二维数组中查找目标值。该方法的思路是遍历数组的每个元素,逐个与目标值进行比较。 具体步骤如下: 从数组的第一行第一列开始,逐行逐列地遍历数组的每个元素。 对

    2024年02月06日
    浏览(91)
  • 剑指offer中算法:二维数组中的查找

    在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 示例 现有矩阵 matrix 如下: { {1, 4, 7}, {2, 5, 8,}, {3, 6, 9} } 给定 target = 9,

    2024年02月12日
    浏览(44)
  • 剑指 Offer 53 - I. 在排序数组中查找数字 I

    题目来源 剑指 Offer 53 - I. 在排序数组中查找数字 I 初始化: 左边界 i=0 ,右边界 j=nums.length−1。 循环二分: 当闭区间 [i, j] 无元素时跳出; 计算中点 m=(i+j)/2 (向下取整); 若 nums[m]target,则 target 在闭区间 [m+1,j] 中,因此执行 i=m+1; 若 nums[m]target,则 target 在闭区间 [i,m−

    2024年02月01日
    浏览(41)
  • 二分查找知识点及练习题

    一、没有相同元素查找 请在一个有序递增数组中(不存在相同元素),采用二分查找,找出值x的位置,如果x在数组中不存在,请输出-1!  输入格式  第一行,一个整数n,代表数组元素个数(n = 600000) 第二行,n个数,代表数组的n个递增元素(1=数组元素值=2000000)  第三

    2024年04月25日
    浏览(38)
  • 代码随想录算法练习Day1:二分查找

    题目链接:704. 二分查找 卡哥视频讲解:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找 二分法概述: 二分法(Binary Search)是一种在有序数组或列表中查找目标元素的算法。 二分法使用前提 : 有序数组或列表 :二分法要求在查找的数据结

    2024年04月23日
    浏览(58)
  • 算法刷题营【Day1】:: 704.二分查找:二分法详谈与相关刷题

    本内容是笔者结合《代码随想录》总结所得,记录学习过程,分享知识! 目录: 1. 开篇例题:704. 二分查找 2. 题解参考(模板写法) - - 2.1 方法一:左闭右闭写法 - - 2.2 方法二:左闭右开写法 3. 模板解释:左闭右闭 - - 3.1 区间划定 - - 3.2 left 、right 移动问题 - - 3.3 循环条件

    2024年02月04日
    浏览(46)
  • 【LeetCode-简单】剑指 Offer 29. 顺时针打印矩阵(详解)

    输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。 示例 1: 示例 2: 剑指 Offer 29. 顺时针打印矩阵 - 力扣(LeetCode) 与 力扣54题相同 54. 螺旋矩阵 二维数组顺时针从外往里走 可以想象成:按照 右-》下-》左 -》上 的顺序一直走,走过的地方不要走即可。

    2024年02月09日
    浏览(54)
  • 【LeetCode-中等】剑指 Offer 29. 顺时针打印矩阵(详解)

    输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。 示例 1: 示例 2: 剑指 Offer 29. 顺时针打印矩阵 - 力扣(LeetCode) 与 力扣54题相同 54. 螺旋矩阵 二维数组顺时针从外往里走 可以想象成:按照 右-》下-》左 -》上 的顺序一直走,走过的地方不要走即可。

    2024年02月13日
    浏览(45)
  • C++二分算法(二分查找&二分答案)细节详解

     二分算法可以分为 二分查找 和 二分答案 。 以在一个 升序数组 中查找一个数为例。它每次考察数组当前部分的 中间元素 ,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,那么左侧的只会更小,不会有所查找的元素,只需到右侧查找;如果

    2024年02月08日
    浏览(53)
  • 【LeetCode-中等】剑指 Offer 31. 栈的压入、弹出序列(详解)

    输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。 示例

    2024年02月13日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包