zoukankan      html  css  js  c++  java
  • 二分查找思路以及可能出现情况对应解决办法

    二分查找

    二分查找又叫折半查找,但是很容易写错,因为不好界定边界

    首先看一道二分查找的题目
     135. 搜索插入位置
    2给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
    3
    4你可以假设数组中无重复元素。
    5
    6示例 1:
    7
    8输入: [1,3,5,6], 5
    9输出: 2
    10示例 2:
    11
    12输入: [1,3,5,6], 2
    13输出: 1
    14示例 3:
    15
    16输入: [1,3,5,6], 7
    17输出: 4
    18示例 4:
    19
    20输入: [1,3,5,6], 0
    21输出: 0
    分析

    二分查找基础条件是建立在有序数组的基础上,本题就是有序数组,然后目标数字与数组中各个值进行比较,

    1. 目标值比第一位元素小
    2. 目标值比最后一位元素大
    3. 目标值介乎于前俩种情况之间
    解法1 暴力

    从第一位遍历与目标值比较,确定位置,此处只说明思路,时间复杂度 o(n)

    解法2 二分查找

    首先说明一下题目中说数组无重复数据,所以暂且不考虑重复情况,重复情况在文末进行说明
    首先确定题中的不变量[left,right],既[0,nums.length-1],左闭右闭区间
    看一下我的写法

     1  /**
    2     * 二分法 首先确定不变量,既不变区间【0,nums.length -1】,左闭右闭区间
    3     * @param nums
    4     * @param target
    5     * @return
    6     */

    7    public int searchInsert(int[] nums, int target) {
    8        int left = 0;
    9        int right = nums.length -1;
    10        while(left <= right){
    11           //避免溢出
    12            int middle  = left + ((right -left)/2);
    13            if(nums[middle]<target){
    14                left = middle + 1;
    15            }else if(nums[middle]>target){
    16                right = middle -1;
    17            }else{
    18                return middle;
    19            }
    20        }
    21        return right+1;
    22    }

    小结
    以上题目主要想说明二分前确定好区间,才能确定好边界条件

    二分查找重复值问题

    当我们遇到[1,2,2,2,2,2]或者[1,1,1,2]这种情况可能会出现死循环该如何解决。
    其实这种情况只会出现在二分查找的第三个判断上,既
    nums[middle] == target

    所以只需要对这块进行处理,既向左以及想有找到所有相同元素的下标,至于要取最左还是最右看你的需求,那么看一下代码

     1else {    //表示arr[mid] == val
    2                /*思路分析
    3                1.在找到mid索引值,不要马上返回
    4                2.向mid索引值的左边扫描,将所有满足1000,的元素的下标, 加入到集合ArrayList
    5                3.向mid索引值的右边扫描,将所有满足1000, 的元素的下标,加入到集合ArrayList
    6                4.将ArrayList返回*/

    7
    8                //向mid左边扫描
    9                int temp = mid - 1;
    10                while (true) {
    11                    if (temp < 0 || arr[temp] != val)//没有找到就退出循环
    12                        break;
    13                    //执行到这里说明找到了,就把找到的元素添加到集合中,继续向左找
    14                    indexList.add(temp);
    15                    temp -= 1;
    16                }
    17                indexList.add(mid);//加入已经找到了的元素【arr[mid]==val】
    18                //向mid右边扫描
    19                temp = mid + 1;
    20                while (true) {
    21                    if (temp > arr.length - 1 || arr[temp] != val)
    22                        break;
    23                    //执行到这里说明找到了,就把找到的元素添加到集合中,继续向右
    24                    indexList.add(temp);
    25                    temp += 1;
    26                }
    27                return indexList;
    28            }

    测试用例 :int[] arr = {1, 2, 3, 5, 6, 6,6, 6, 7, 8, 9};
    target = 6;
    返回的 indexList 就是 [4,5,6,7]既为数组中为6的下标;

    总结

    二分查找

    1. 注意边界条件
    2. 注意为有序数组
    3. 注意数组是否有重复元素
      确定以上问题之后二分问题就能迎刃而解了
    不会,我可以学;落后,我可以追赶;跌倒,我可以站起来!
  • 相关阅读:
    python-生成器
    python—迭代器
    python—递归函数
    CentOS关闭防火墙
    OpenHCI
    USB电源管理
    USB相关的网络资料
    USB Packet Types
    USB描述符概述
    Core Java Volume I — 1.2. The Java "White Paper" Buzzwords
  • 原文地址:https://www.cnblogs.com/xiaoshahai/p/14298504.html
Copyright © 2011-2022 走看看