LeetCode练习——704.二分查找(C++)

题目链接

二分查找

题目描述

给定一个 n n n个元素有序的(升序)整型数组 n u m s nums nums和一个目标值 t a r g e t target target,写一个函数搜索 n u m s nums nums中的 t a r g e t target target,如果目标值存在返回下标,否则返回 − 1 -1 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. 你可以假设 n u m s nums nums中的所有元素是不重复的。
  2. n n n将在 [ 1 , 10000 ] [1, 10000] [1,10000]之间。
  3. n u m s nums nums的每个元素都将在$[-9999, 9999]之间。

思路

二分法思想

二分法是一种在有序数组中查找特定元素的搜索算法,要实现二分法,前提条件是用于搜索的数组必须是有序的而且数组中没有重复元素
其核心思想是:每次查找缩小一般的查找范围,直到找到目标值或搜索完数组。
步骤:(默认数组是递增的)

  • 首先选择数组中间的数字和要查找的目标值进行比较;
  • 如果相等,说明找到了我们要找的目标值,直接返回该元素的下标;
  • 如果不相等:
    • 如果中间的数字大于目标值,则将搜索范围缩小到中间数字左边的部分,右边部分全部排除。
    • 如果中间的数字小于目标值,则将搜索范围缩小到中间数字右边的部分,左边部分全部排除。
  • 对剩余部分重复以上操作,直到找到目标值或者搜索玩数组,方可结束。

二分法区间一般右两种写法,左闭右闭 [ l e f t , r i g h t ] [left, right] [left,right]左闭右开 [ l e f t , r i g h t ) [left, right) [left,right)

第一种写法(左闭右闭)即 [ l e f t , r i g h t ] [left, right] [left,right]

  • 由于 l e f t = = r i g h t left == right left==right是有意义的,所以此时在 w h i l e while while循环中要使用 < = <= <=,即要用 w h i l e ( l e f t < = r i g h t ) while (left <= right) while(left<=right)
  • i f ( n u m s [ m i d d l e ] < t a r g e t ) if (nums[middle] < target) if(nums[middle]<target) l e f t left left要赋值 m i d d l e + 1 middle + 1 middle+1,因为 n u m s [ m i d d l e ] nums[middle] nums[middle]一定不是要找的目标值 t a r g e t target target,而且 t a r g e t target target的值一定比 n u m s [ m i d d l e ] nums[middle] nums[middle]大。
  • 同理 i f ( n u m s [ m i d d l e ] > t a r g e t ) if (nums[middle] > target) if(nums[middle]>target) r i g h t right right要赋值 m i d d l e − 1 middle - 1 middle1,因为 n u m s [ m i d d l e ] nums[middle] nums[middle]一定不是要找的目标值 t a r g e t target target,而且 t a r g e t target target的值一定比 n u m s [ m i d d l e ] nums[middle] nums[middle]小。

第二种写法(左闭右开)即 [ l e f t , r i g h t ) [left, right) [left,right)

  • 由于 l e f t = = r i g h t left == right left==right是没有意义的,所以此时在 w h i l e while while循环中要使用 < < <,即要用 w h i l e ( l e f t < = r i g h t ) while (left <=right) while(left<=right)
  • i f ( n u m s [ m i d d l e ] < t a r g e t ) if (nums[middle] < target) if(nums[middle]<target) l e f t left left要赋值 m i d d l e + 1 middle + 1 middle+1,因为 n u m s [ m i d d l e ] nums[middle] nums[middle]一定不是要找的目标值 t a r g e t target target,而且 t a r g e t target target的值一定比 n u m s [ m i d d l e ] nums[middle] nums[middle]大。
  • 同理 i f ( n u m s [ m i d d l e ] > t a r g e t ) if (nums[middle] > target) if(nums[middle]>target) r i g h t right right要赋值 m i d d l e middle middle,因为 n u m s [ m i d d l e ] nums[middle] nums[middle]一定不是要找的目标值 t a r g e t target target,而且 t a r g e t target target的值一定比 n u m s [ m i d d l e ] nums[middle] nums[middle]小,而且下一个搜索区间不会比较 n u m s [ m i d d l e ] nums[middle] nums[middle],所以 r i g h t right right需要赋值 m i d d l e middle middle

题解代码

第一种写法

class Solution {
public:
    int search(vector<int>& nums, int target) {
    	// 定义左边界
        int left = 0;
        // 定义有边界
        int right = nums.size() - 1;
		
        while (left <= right) {
            int middle = (left + right) / 2;
            // 中间的数比target小,left赋值middle + 1
            if (nums[middle] < target) {
                left = middle + 1;
            }
            // 中间的数比target大,left赋值middle - 1
            else if (nums[middle] > target) {
                right = middle - 1;
            }
            // 找到目标值,返回该元素在数组中的下标
            else {
                return middle;
            }
        }
        // 目标值不再数组中,返回-1
        return -1;
    }
};
  • 时间复杂度为:O(n)
  • 空间复杂度为:O(1)

第二种写法

class Solution {
public:
    int search(vector<int>& nums, int target) {
    	// 定义左边界
        int left = 0;
        // 定义有边界
        int right = nums.size();

        while (left < right) {
            int middle = (left + right) / 2;
            // 中间的数比target小,left赋值middle + 1
            if (nums[middle] < target) {
                left = middle + 1;
            }
            // 中间的数比target大,right赋值middle
            else if (nums[middle] > target) {
                right = middle;
            }
            // 找到目标值,返回该元素在数组中的下标
            else {
                return middle;
            }
        }
        // 目标值不再数组中,返回-1
        return -1;
    }
};
  • 时间复杂度为:O(n)
  • 空间复杂度为:O(1)

总结

二分法是很基础而且很重要的一个算法,在使用时要特别注意区间的选择,以及不同区间循环条件的使用和循环变量的更新。

本文相关信息:
参考视频:哔哩哔哩—代码随想录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值