zoukankan      html  css  js  c++  java
  • 算法题16 二分查找及相关题目

      二分查找思想就是取中间的数缩小查找范围,对应不同的题目变形,在取到中间数mid确定下一个查找范围时也有不同,左边界有的low=mid+1,也可能low=mid,右边界有的high=mid-1,也有可能high=mid。

    对于一个排序数组来说二分查找的时间复杂度是O(logn)

    1. 二分查找法

     1  int BinarySearch(int arr[],int len,int target)
     2  {
     3      if (arr==NULL||len<=0)
     4          throw std::exception("Invalid input.");
     5      int low=0,high=len-1;
     6      while(low < high)
     7      {
     8          int mid = low+(high-low)/2;
     9          if (arr[mid]>target)
    10              high = mid-1;
    11          else if (arr[mid]<target)
    12              low = mid + 1;
    13          else //find the target
    14              return mid;
    15      }
    16      //the array does not contain the target
    17      return -1;
    18  }

    2.二分查找之寻找边界

      这种边界的寻找分为2种:最后1个小于某数的值,低边界;第1个大于某数的值,高边界,情况不同在遍历查找时边界的调整也不同。

     1)最后1个小于某数的值

     1  int FindLastSmallerNum(int arr[],int len,int target)
     2  {
     3      if (arr==NULL||len<=0)
     4          throw std::exception("Invalid input.");
     5 
     6      int low=0,high=len-1;
     7      while(low<high)
     8      {
     9          int mid = low+(high-low)/2;
    10          //大于等于的时候边界往前移
    11          if (arr[mid]>=target)
    12              high=mid-1;
    13          //小于的时候边界mid处多移1步有可能将小值跳过去,因此调整到mid处
    14          else if (arr[mid]<target)
    15              low=mid;
    16          //判断high是否已经小于目标值
    17          if (arr[high]<target)
    18          {
    19              return arr[high];
    20          }
    21      }
    22 
    23      return -1;
    24  }

      2) 第1个大于某数的值

     1  int FindFirstBiggerNum(int arr[],int len,int target)
     2  {
     3      if (arr==NULL||len<=0)
     4          throw std::exception("Invalid input.");
     5 
     6      int low=0,high=len-1;
     7      while(low<high)
     8      {
     9          int mid = low+(high-low)/2;
    10          //大于等于的时候边界往前移
    11          if (arr[mid]>target)
    12              high=mid;
    13          //小于的时候边界mid处多移1步有可能将小值跳过去,因此调整到mid处
    14          else if (arr[mid]<=target)
    15              low=mid+1;
    16          //判断high是否已经小于目标值
    17          if (arr[low]>target)
    18          {
    19              return arr[low];
    20          }
    21      }
    22 
    23      return -1;
    24  }

    3. 二分查找之旋转数组的最小数字

      把一个数组最开始的若干个元素搬到数组的末尾, 我们称之数组的旋转。输入一个递增排序的数组的一个旋转, 输出旋转数组的最小元素。例如数组{3,4, 5, 1, 2 }为{ 1,2,3, 4,5}的一个旋转,该数组的最小值为 1。

    仔细观察会发现旋转数组的最小值左边的数都大于最后一个数,右边的数都小于等于最后一个数,那么在二分查找的过程中与最后一个数比较来调整查找区间即可

     1  int FindMinNum(int arr[],int len)
     2  {
     3      if (arr==NULL||len<=0)
     4          throw std::exception("Invalid input.");
     5 
     6      int lo=0,hi=len-1;
     7      int mid=0;
     8      while (lo<hi)
     9      {
    10          mid=lo+(hi-lo)/2;
    11          if (arr[mid]>arr[hi])
    12          {
    13              lo=mid+1;
    14          }else if (arr[mid]<=arr[hi])
    15          {
    16              hi=mid;
    17          }
    18      }
    19      return arr[lo];
    20  }

      关于二分查找,http://www.cnblogs.com/ider/archive/2012/04/01/binary_search.html 这篇博客也有很好的总结。

    引述该博客:

    二分查找法的缺陷

      二分查找法的O(log n)让它成为十分高效的算法。不过它的缺陷却也是那么明显的。就在它的限定之上:有序。

      我们很难保证我们的数组都是有序的。当然可以在构建数组的时候进行排序,可是又落到了第二个瓶颈上:它必须是数组

      数组读取效率是O(1),可是它的插入和删除某个元素的效率却是O(n)。因而导致构建有序数组变成低效的事情。

      解决这些缺陷问题更好的方法应该是使用二叉查找树了,最好自然是自平衡二叉查找树了,自能高效的(O(n log n))构建有序元素集合,又能如同二分查找法一样快速(O(log n))的搜寻目标数。

  • 相关阅读:
    HDMI介绍与流程
    HDMI热插拔检测原理
    在AES标准规范中,分组长度、密钥长度的关系
    WORD-每5行添加一个行号
    FreeRTOS 调试方法(printf---打印任务执行情况)
    SELinux深入理解
    一文彻底明白linux中的selinux到底是什么
    云锵投资 2020 年 06 月简报
    ubuntu16.04 安装opencv-2.4.9
    Windows高DPI系列控件(二)
  • 原文地址:https://www.cnblogs.com/wangzaizhen/p/5182005.html
Copyright © 2011-2022 走看看