09 |「整数二分」算法简析

本文介绍了二分查找算法的基本思路,通过一个LeetCode704题目的例子详细解析了算法的实现,包括确定区间、定义性质、更新区间、源码分析以及时间复杂度。此外,还提供了两个课后习题——搜索插入位置和查找数字的问题,讨论了不同场景下二分法的应用。

前言

            今天算法内容是 二分法

一、例题

1、题目

LeetCode 704. 二分查找 原题链接

2、算法思路

1)二分的本质是寻找区间边界。

2)给定一个区间,在这个区间上定义了某种性质,在右半边区间满足这个性质,在左半边区间不满足,如果可以找到这样一个性质,可以将整个区间被一分为二。

3)这样,二分就可以寻找这个性质的边界点,既可以寻找出来红色边界点,也可以寻找出绿色的边界点。

3、解题步骤

  • 1)确定 mid
  • 2)定义一个性质,可以将区间划为两部分,一半边满足性质(假定这半边区间为绿色),另一半边不满足性质(假定这半边区间为红色)。
  • 3)更新区间。

4、源码剖析

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size();
        int l = 0, r = n - 1;                 //(1)
        
        while (l < r)
        {
            int mid = l + r >> 1;     		  //(2)
            if (nums[mid] >= target)          //(3)
            	r = mid;  			          //(4)
            else l = mid + 1;  		          //(5)
        }
        if (nums[l] == target) return r;	  //(6)
        return -1;           				  //(7)
    }
};
  • (1)确定整个区间 [l, r]
  • (2)确定 mid
  • (3)定义性质 >= target,并进行判断;
  • (4)判断结果为 true 时,通过 r = mid,更新 [l, r] 为新区间;
  • (5)判断结果为 false 时,通过 l = mid + 1,更新 [l, mid + 1] 为新区间;
  • (6)当 l = r 时,循环结束,判断 target 是否存在,返回 lr 均可;
  • (7)当 target 不存在,返回 -1

5、时间复杂度

O ( l o g n ) O(log n) O(logn)

6、注意点

  • 1)为什么是 r = mid? 当 nums[mid] 满足 >= target 性质时,mid 在绿色区间中,那么答案在 [l, mid]mid 可能是答案,所以通过 r = mid 更新区间为 [l, mid]
  • 2)为什么是 l = mid + 1?当 nums[mid] 不满足 >= target 性质时,mid 在红色区间中,那么答案在 [mid + 1, r]mid 不可能是答案,不能包括在内,所以通过 l = mid + 1 更新区间为 [mid + 1, r]

二、课后习题

习题1: LeetCode 35. 搜索插入位置 原题链接

( 1 ) (1) (1) 找到满足 >=target的第一个数,如果所有数都 <=target则插入到最后一个位置;
( 2 ) (2) (2) 插入的位置可能 等于 nums.size(),在插入了target元素后整个数组的长度变为nums.size() + 1,所以两个指针的初始位置应该是 int l = 0, r = nums.size(); 而不是 int l = 0, r = nums.size() - 1

// 参考代码
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l = 0, r = nums.size(); // 插入的位置可能是 nums.size()
        while (l < r) {
            int mid = l + r >> 1;
            if (nums[mid] >= target) r = mid;
            else l = mid + 1;
        }
        return l;
    }
};

习题2: LeetCode 剑指 Offer 53 - I. 在排序数组中查找数字 I 原题链接

( 1 ) (1) (1) 找到满足 >=target性质的左边界 left
( 2 ) (2) (2) 找到满足 <=target性质的有边界right
( 3 ) (3) (3) 左边界 left和右边界 right中的个数就等于 target的个数;

class Solution {
public:
   int search(vector<int>& nums, int target) {
       if (nums.empty()) return 0;
       int n = nums.size();
       // 找到满足性质的左边界
       int left = -1, right = n;
       int l = 0, r = n - 1;
       while (l < r) {
           int mid = (l + r) >> 1;
           if (nums[mid] >= target) r = mid;
           else l = mid + 1;
       }
       if (nums[l] != target) return 0;
       else 
       {
           left = l;
           l = 0, r = n - 1;
           while (l < r) {
               int mid = (l + r + 1) >> 1;
               if (nums[mid] <= target) l = mid;
               else r = mid - 1;
           }
           right = l;
       }

       return right - left + 1;
   }
};
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个写代码的修车工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值