前言
今天算法内容是 二分法
一、例题
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是否存在,返回l和r均可; - (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;
}
};
本文介绍了二分查找算法的基本思路,通过一个LeetCode704题目的例子详细解析了算法的实现,包括确定区间、定义性质、更新区间、源码分析以及时间复杂度。此外,还提供了两个课后习题——搜索插入位置和查找数字的问题,讨论了不同场景下二分法的应用。
1505

被折叠的 条评论
为什么被折叠?



