【Leetcode刷题】:算法入门__二分查找

190 阅读3分钟

1.题目要求:

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target写一个函数 搜索 nums 中的 target,如果目标值存在,则返回下标,否则返回-1

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9

输出: 4

解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2

输出: -1

解释: 2 不存在 nums 中因此返回 -1

提示:

  1. 你可以假设 nums 中的所有元素是不重复的。
  2. n 将在 [1, 10000]之间。
  3. nums 的每个元素都将在 [-9999,9999]之间。

想看【leetcode原题】?,请点这里前往


2.解题思路:

  • 如果数组是有序的,而且也没有重复的元素(元素重复的话会使返回的下标不唯一)。那么就满足了使用二分查找的前提条件。我们可以使用二分法查找某个目标值。

  • 我们先定义两个变量存放数组首尾元素的下标firstend,

  • first = 0

  • 然而!end的取值却可以有两种:

  • 第一种int end = nums.size() - 1;

  • 这种方法让我们在左闭右闭的区间[first,end]里寻找目标值target

  • 第二种int end = nums.size();

  • 这种方法让我们在左闭右开的区间[first,end)里寻找目标值target

  • 这两种end的取值关系到边界条件的设定,即区间的定义。

  • 两种区间又各自决定着循环或选择语句该怎么写:

  • 即到底是 while(first < end) 还是 while(first <= end) ,到底是first = middle呢,还是要first = middle - 1等等。

  • 然后就是中间变量middle的定义,即int middle = first + ((end - first)/2);

  • 在这里,并不推荐使用语句middle = (first + end) / 2,因为当firstend都过大时,可能会造成数据溢出,进而导致middle出错。所以我们推荐使用语句int middle = first + ((end - first)/2);来定义middle。

  • 接下来就是循环条件和判断条件的编写了

  • 每次判断,都把无效的边界点去掉,逐渐逼近目标值。在循环中,要么找到了目标值,返回下标middle。要么没有找到目标值,返回-1。

3.解题方法一:

C++解题:

二分查找.png

分析:

  • int end= nums.size() - 1;
  • 定义了target在区间 [first,end]中,即左闭右闭的区间上
  • while (first <= end)
  • first等于end时,区间 [first,end]仍有效,所以用**<=**
  • if (nums[middle] > target) end = middle - 1;
  • 这表明target数组的左半边,所以更新区间为:[first , middle - 1]
  • else if (nums[middle] < target) first = middle + 1;
  • 这表明target数组的右半边,所以更新区间为:[middle + 1, end]
  • else return middle;
  • 这表明数组中找到目标值,直接返回下标,即nums[middle] == target
  • 在循环外头return -1表明在循环里未找到目标值,所以返回-1。

4.解题方法二:

二分查找02.png

分析:

  • int end= nums.size();
  • 定义了target在区间 [first,end)中,即左闭右开的区间上
  • while (first < end)
  • 因为在这里first不会等于end,所以我们使用 < 来作为循环条件。
  • if (nums[middle] > target) end = middle;
  • 这里的end并不是赋值为middle-1
  • else if (nums[middle] < target) first = middle + 1;
  • 这表明target数组的右半边,所以更新区间为:[middle + 1, end)
  • else return middle;
  • 这表明数组中找到目标值,直接返回下标,即nums[middle] == target
  • 在循环外头return -1表明在循环里未找到目标值,所以返回-1。

5.总结:

使用二分查找的前提条件:

  • 元素有顺序地存储
  • 元素按关键字顺序存储

基本思想:

  • 数组a中的元素按顺序排列
  • 将数组分为两半,个数相同
  • 取中间数值a[n/2]与想要查找的元素x作比较
  • 若a[n/2]大于x,那么继续在左区间里查找x
  • 若a[n/2]小于x,那么继续在右区间里查找x
  • 若a[n/2]==x,则找到了x