【面试必刷101】二分查找

摘要

【面试必刷101】系列blog目的在于总结面试必刷101中有意思、可能在面试中会被考到的习题。总结通用性的解题方法,针对特殊的习题总结思路。既是写给自己复习使用,也希望与大家交流。

【面试必刷101】递归/回溯算法总结I(十分钟理解回溯算法)
【面试必刷101】递归/回溯算法总结II(十分钟刷爆回溯算法题)
【面试必刷101】链表
【面试必刷101】二叉树

1 基础知识

二分查找首先是要满足二分的性质,啥性质呢?target点左边全部满足一类条件,target点右边全部不满足一类条件,而且能够通过条件判别目标的target是在左区间还是右区间。

二分查找用的最多的是有序的数组。看下图中的题目:

在这里插入图片描述
查找target的上界和下界的差异在于:看这个数是出现在左区间还是出现在右区间。如果是查找下界,那么只可能出现在左区间,有点像夹逼准则,左边夹逼出最小值,右边夹逼出最大值。

然后就会涉及到两个模板,左区间的模板和右区间的模板。很容易记住,两者的差别就在于计算mid的时候是否加1,左区间不加,右区间加1。

1.1 查找值在左区间

区间[l, r]被划分成 [l, mid][mid + 1, r]时使用:

      // 首先是查找下界,是要在左边找
      int l = 0, r = n - 1, mid = 0;
      while (l < r) {
          mid = l + ((r - l) >> 1);
          if (arr[mid] >= x) {
              r = mid;
          } else {
              l = mid + 1;
          }
      }

1.2 查找上界

区间[l, r]被划分成[l, mid - 1][mid, r]时使用:

      // 接下来查找上界,是要在右边找
      l = 0; r = n - 1;
      while (l < r) {
          mid = l + ((r - l + 1) >> 1);
          if (arr[mid] <= x) {
              l = mid;
          } else {
              r = mid - 1;
          }
      }

2 面试必刷习题

2.1 二维数组中的查找

二维数组中的查找
在这里插入图片描述
谁能想到找个暑期实习这个题居然被考了两回,发现面试的题不一定难,但代码量一般会比较少,思路很重要。

public class Solution {
    public boolean Find(int target, int [][] array) {
        int row = array.length;
        int col = array[0].length;
        int i = 0, j = col - 1;
        while (i < row && j > -1) {
            if (array[i][j] == target) {
                return true;
            } else if (array[i][j] > target) {
                j--;
            } else {
                i++;
            }
        }
        return false;
    }
}

2.2 旋转数组中的最小数字

旋转数组中的最小数字
在这里插入图片描述

这里非得和右边比,有点无奈。

import java.util.*;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        int l = 0, r = array.length - 1;
        while (l < r) {
            int mid = l + ((r - l) >> 1);
            if (array[mid] > array[r]) {
                l = mid + 1;
            } else if (array[mid] < array[r]) {
                r = mid;
            } else {
                --r;
            }
        }
        return array[l];
    }
}

我非要和左边比

import java.util.*;
import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        // 求数组中的最小值
        int l = 0, r = array.length - 1;
        while (l < r) {
            if (array[r] > array[l]) return array[l];
            int mid = l + ((r - l) >> 1);
            if (array[mid] > array[l]) {
                l = mid + 1;
            } else if (array[mid] < array[l]) {
                r = mid;
            } else {
                ++l;
            }
        }
        return array[l];
    }
}

这个老哥就不同,直接理解为与第一个的比较。这种思路比较符合我的特点。这个思路非常非常good,这才是二分该有的思路。
在这里插入图片描述
图中水平的实线段表示相同元素。
我们发现除了最后水平的一段(黄色水平那段)之外,其余部分满足二分性质:
竖直虚线左边的数满足rotateArray[i]≥rotateArray[0]暨nums[i]≥nums[0];
而竖直虚线右边的数不满足这个条件。分界点就是整个数组的最小值。所以我们先将最后水平的一段删除即可。
另外,不要忘记处理数组完全单调的特殊情况:删除最后水平的一段之后,如果剩下的最后一个数大于等于第一个数,则说明数组完全单调。

import java.util.*;
import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        int l = 0, r = array.length - 1;
        //while (l < array.length - 1 && array[l + 1] == array[l]) l++;
        while (r > 0 && array[r] == array[0]) r--;
        if (array[r] >= array[l]) return array[l];
        while (l < r) {
            int mid = l + ((r - l) >> 1);
            if (array[mid] >= array[0]) {
                l = mid + 1;
            } else {
                r = mid;
            }
        }
        return array[l];
    }
}

3 知识点总结

二分查找的边界处理还是很麻烦,所以建议记一下那两个模板,对于其他两道题就比较灵活了,需要抓住二分的特点,实在不行记一下吧。

4 总结

焦虑了就休息下。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值