• 【LeetCode-查找】二分查找


    题目描述

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

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

    注意:

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

    题目链接: https://leetcode-cn.com/problems/binary-search/

    思路

    经典的二分查找问题。二分查找的难点在于不容易写对,也就是不容易判断应该使用 < 还是 <=,还有要不要 +1,-1 的问题。二分查找主要有两种写法:

    写法一

    class Solution {
    public:
        int search(vector<int>& nums, int target) {
            if(nums.empty()) return -1;
    
            int left = 0, right = nums.size()-1;
            while(left<=right){
                int mid = left + (right-left)/2;    // 防止溢出
                if(nums[mid]==target) return mid;
                else if(nums[mid]>target){
                    right = mid-1;
                }
                else if(nums[mid]<target){
                    left = mid+1;
                }
            }
            return -1;
        }
    };
    

    写法二

    class Solution {
    public:
        int search(vector<int>& nums, int target) {
            if(nums.empty()) return -1;
    
            int left = 0, right = nums.size();
            while(left<right){
                int mid = left + (right-left)/2;    // 防止溢出
                if(nums[mid]==target) return mid;
                else if(nums[mid]>target){
                    right = mid;
                }
                else if(nums[mid]<target){
                    left = mid+1;
                }
            }
            return -1;
        }
    };
    

    两种写法的不同体现在3个方面,如下图:

    3处不同分别是:

    • right的初始化;
    • while循环条件;
    • right的更新方式;

    3处不同的原因取决于我们的搜索范围是[left, right]还是[left, right)。下面分析两种不同写法的区别以及原因:

    • 对于写法1,right初始化为nums.size()-1,意味着搜索的范围为[left, right],因为nums.size()-1指向nums的最后一个元素,如果搜索范围是[left, right)的话,最后一个数字就不在搜索范围了。在搜索范围为[left, right]的情况下,left==right也就是[left, left]这样的范围是有意义的,例如[2,2]意味着对下标为2的数字进行搜索,所以while的条件为left<=right。在搜索的过程中,我们根据mid指向的元素与target之间的大小关系来选择接下来的搜索范围,因为搜索范围是[left, right],所以在更新时right要更新为mid-1,如果不减一的话,下一步搜索的范围就包含mid了。

    • 对于写法2,right初始化为nums.size(),意味着搜索范围为[left, right),因为right初始指向num.size(),也就是nums最后一个数字的下一个位置,[left, right)不包含right指向的元素,刚好搜索范围是整个数组。在搜索范围是[left, right)的情况下,left==right也就是[left, left)这样的条件是无意义的,所以while的条件为left<right。因为搜索范围是左闭右开,不包含right指向的元素,所以right=mid即可,无需更新为mid-1,因为mid不会被包含进搜索范围中。

    参考

    1、https://leetcode-cn.com/problems/binary-search/solution/er-fen-cha-zhao-de-xun-huan-bu-bian-liang-zhi-yao-/

  • 相关阅读:
    应用层协议及ip地址划分
    请求与响应编码及jsp基本原理
    springboot注解
    springboot 快速入门
    Http协议简单解析及web请求过程
    Tomcat原理详解及请求过程
    mysql数据库乱码的问题解决
    AOP的实现原理
    Springl利用Aspectj的扩展实现Aop
    JDK动态代理实现原理
  • 原文地址:https://www.cnblogs.com/flix/p/12802877.html
Copyright © 2020-2023  润新知