二分查找-一种效率较高的查找方法

举报
i进击的攻城狮 发表于 2022/08/11 23:09:26 2022/08/11
【摘要】 一、二分查找概述二分查找是一种相比于逐个查找,性能更加优秀,时间复杂度更低的一种算法。二分查找的思路是,对一个顺序的集合,确定查找区间的左右边界,再根据左右边界,计算出中间的值,再和中间值进行比较,如果左边界大于中间值,左边界向右移动到中间值+1的位置,反之右边界移动的中间值左边的位置。事例示例一:输入: nums = [-1,0,3,5,9,12], target = 9输出: 4解释:...

一、二分查找概述

二分查找是一种相比于逐个查找,性能更加优秀,时间复杂度更低的一种算法。
二分查找的思路是,对一个顺序的集合,确定查找区间的左右边界,再根据左右边界,计算出中间的值,再和中间值进行比较,如果左边界大于中间值,左边界向右移动到中间值+1的位置,反之右边界移动的中间值左边的位置。
事例

示例一:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

首先左边界left是0,右边界right是5,
mid中间值计算公式是:
**(right-left) / 2 + left **= (5-0)/2 + 0 = 2.5,向下取整为2。
这里要注意,一般二分查找中,mid中间下标计算结果是小数,都是向下取整。
nums[2] = 3;
3 小于 target 9,可以判断目标值在右区间。
left = mid + 1;
left改变后重新计算下标,计算中间下标值是:
(5-3)/2 +3 = 4;此时nums[4] = 9;
找到目标值。
代码如下

class Solution {
    public int search(int[] nums, int target) {
        int l = 0;
        int r = nums.length-1;

        while (l<=r){
            int m = (r-l)+l;
            if (nums[m]==target){
                return m;
            }else if (target<nums[m]){
                r = m-1;
            }else {
                l = m+1;
            }
            
        }
        return -1;
    }
}

二、分查找解决算法问题

二分查找并不是只是简简单单的去判断一个数组中,是否存在目标值,它是一种解决问题的思想。二分查找能衍生出一些算法问题。接下来由如下三个模板,去了解如何用二分查找去解决问题。

2.1 模板I(标准模板)

int binarySearch(int[] nums, int target){
  if(nums == null || nums.length == 0)
    return -1;

  int left = 0, right = nums.length - 1;
  while(left <= right){
    // Prevent (left + right) overflow
    int mid = left + (right - left) / 2;
    if(nums[mid] == target){ return mid; }
    else if(nums[mid] < target) { left = mid + 1; }
    else { right = mid - 1; }
  }

  // End Condition: left > right
  return -1;
}

模板1是二分查找的最基础和最基本的形式。这是一个标准的二分查找模板,大多数高中或大学会在他们第一次教学生计算机科学时使用。模板 1 用于查找可以通过访问数组中的单个索引来确定的元素或条件。
在这个模板中,left和right会不断靠近,最后一次遍历的时候,两个值left和right会相等。

x 的平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例 1:
输入:x = 4
输出:2

思路
在从1到x中寻找x的平方根,
如果mid的平方大于x,那么right = mid - 1 同理,反之就是left = mid + 1
代码:

public int mySqrt(int x) {
        if (x==0){return 0;}
        if (x==1){return 1;}
        int l = 0;
        int r = x;
        while(l<=r){
            int m = (r-l)/2+l;
            if (x/m==m){
                return m;
            }else if(x/m<m){  // 16 / 8 < 8
                r = m-1;

            }else if(x/m>m){
                l = m + 1;
            }

        }
        return r;

    }

2.2 二分查找模板 II

分查找的高级模板。它用于查找需要访问数组中当前索引及其直接右邻居索引的元素或条件。

int binarySearch(int[] nums, int target){
  if(nums == null || nums.length == 0)
    return -1;

  int left = 0, right = nums.length;
  while(left < right){
    // Prevent (left + right) overflow
    int mid = left + (right - left) / 2;
    if(nums[mid] == target){ return mid; }
    else if(nums[mid] < target) { left = mid + 1; }
    else { right = mid; }
  }

  // Post-processing:
  // End Condition: left == right
  if(left != nums.length && nums[left] == target) return left;
  return -1;
}

关键属性

  • 一种实现二分查找的高级方法。
  • 查找条件需要访问元素的直接右邻居。
  • 使用元素的右邻居来确定是否满足条件,并决定是向左还是向右。
  • 保证查找空间在每一步中至少有 2 个元素。
  • 需要进行后处理。 当你剩下 1 个元素时,循环 / 递归结束。 需要评估剩余元素是否符合条件。

2.3 二分查找模板 III

模板 3 是二分查找的另一种独特形式。 它用于搜索需要访问当前索引及其在数组中的直接左右邻居索引的元素或条件。

int binarySearch(int[] nums, int target) {
  if (nums == null || nums.length == 0)
      return -1;

  int left = 0, right = nums.length - 1;
  while (left + 1 < right){
      // Prevent (left + right) overflow
      int mid = left + (right - left) / 2;
      if (nums[mid] == target) {
          return mid;
      } else if (nums[mid] < target) {
          left = mid;
      } else {
          right = mid;
      }
  }

  // Post-processing:
  // End Condition: left + 1 == right
  if(nums[left] == target) return left;
  if(nums[right] == target) return right;
  return -1;
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。