【leetcode/二分】二分查找(二分查找模板题)

一. 问题描述:

就是一个有序数组,给定一个数字,存在的话返回下标,不存在的话返回-1;

二. 两种递归实现对比:

这道题首先应该想到的就是递归实现。

我这里所提到的两种递归实现其实就是把数组分段——一种是分为左闭右开的形式,另一种是两边都闭的形式。

· 左闭右开

int BinarySearch(vector<int> &nums, int l, int r, int target) {
  // 不是你想象地那么完美
  if (l == r) return -1;
  int m = l + (r - l) / 2;        // 防止溢出
  // 建议还是把这个判断放在最前面
  if (target == nums[m]) return m;
  else if (target > nums[m]) return BinarySearch(nums, m + 1, r, target);
  else if (target < nums[m]) return BinarySearch(nums, l, m, target);
}
  1.  优势判断终止的时候特别方便,两个指针碰到一起,就结束了。
  2.  劣势:我们左闭右开其实是把一个[a, b)的区间能过完美地分为[a, c), [c, b)这两个部分。然而这里并派不上用场——因为我还要挖掉中间一个元素,这就看上去很不和谐。

· 左右都闭

int BinarySearch(vector<int> &a, int l, int r, int target) {
  if (l > r) return -1;
  int m = l + (r - l) / 2;        // 防止溢出
  if (target == a[m]) return m;
  else if (target > a[m]) return BS(a, m + 1, r, target);
  else if (target < a[m]) return BS(a, l, m - 1, target);
}

我思前想后,发现这种写法没什么劣势。m + 1和m - 1充分体现了挖掉中间这个元素的处理

唯独要注意的是l == r的时候可能还要进行处理

三. 非递归实现

递归实现简单地令人发指。于是我们就寻思着有无非递归的实现

大家看到这时一个尾递归,所以我们无需引入栈。只要相应的循环即可。

实现也特别简单,我这里就使用之前觉得没什么缺陷的左闭右闭来实现了。

int BinarySearch(vector<int> &a, int target) {
  // 左闭右也闭的形式
  int l = 0;
  int r = a.size() - 1;
  while (l <= r) {
    int m = l + (r - l) / 2;        // 防止溢出
    if (target == a[m]) return m;
    else if (target > a[m]) l = m + 1;
    else if (target < a[m]) r = m - 1;
  }  
  return -1;
}

四. 其它经验

  1. 注意把中间的元素挖掉
  2. 利用l + (r - l) / 2防止加法溢出
发布了137 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43338695/article/details/102765013