一、数组介绍
数组是存放在连续内存空间上的相同类型数据的集合。
• 数组下标都是从0开始的。
• 数组内存空间的地址是连续的
一维数组
二维数组
在C++中二维数组在地址空间上是连续的
二、二分算法介绍
给定一个排序数组nums和一个目标值target,在数组中找到目标值,并返回其索引(下标)。如果目标值不存在于数组中,就返回-1。
搞定二分法主要是要解决两个问题:
-
left、right值的初始值及其变化情况
-
left、right与target值的大小关系(≥ > < ≤ )
在解决这两个问题前,我们需要先知道集给定数组的取值区间的开闭情况:
(1)左闭右闭
(2)左闭右开
PS:不会出现左开右闭的情况
(1)左闭右闭
当数组区间为左闭右闭时,left、right的两个注意点的情况是:
- left、right的初始值分别是:left = 0,right = num.szie - 1
- while语句的条件表达式是left ≤ right;而 if 判定后的right和left的变化情况是:right = middle - 1,left = middle + 1
我们可以举例子来理解,假定数组是[1,1],那么left与right是可能存在相等的情况的,这样的话,我们在while的条件表达式,也应该考虑到right和left相等的情况,所以此时的条件表达式应该为 left ≤ right;
同样的,因为右边值是可以取到的(闭区间),所以right的初始值要从数组长度-1开始;
而当nums[middle]大于target时:
那么此时我们要更新right,而因为我们已经拿nums[middle]的值和target比较过了,且没有找到target对应下标,所以为了更好的处理数组的区间值,我们需要去掉比较过的middle对应值,而又因为是闭区间,所以我们需要让right = middle - 1;同样的理解,left = middle + 1
此时的伪代码如下:
left = 0
right = num.szie - 1
while (left ≤ right) {
middle = (left + right) / 2
// 为了防止溢出,middle = (left + right) / 2可以改为left + (right - left) / 2
if (nums[target] > target)
right = middle - 1;
else if (nums[target] < target)
left = middle + 1;
else return middle;
}
return -1;
(2)左闭右开
当数组区间为左闭右开时,left、right的两个注意点的情况是:
- left、right的初始值分别是:left = 0,right = num.szie
- while语句的条件表达式是left < right;而 if 判定后的right和left的变化情况是:right = middle ,left = middle
同样的,我们也可以举例子说理解,假定数组是[1,1), 这个时候left = right,但1怎么会小于1呢?也就是left是不能等于right的,所以while语句的条件表达式是:left < right;
同样的,因为数组右边是开区间,如果我们将right的初始值从num.szie - 1开始的话,那么数组最右边值就无法取到,所以right的初始值为num.szie;
同样的,当nums[middle]大于target时:
我们也将nums[middle]的值和target比较过了,并且没有找到target对应下标,但是因为数组的右边是开区间,我们只用令right = middle就好,这样就不会取到已经比较过的middle值了;同样的,left的取值为:left = middle
此时的伪代码如下:
left = 0
right = num.szie
while (left < right) {
middle = (left + right) / 2
// 为了防止溢出,middle = (left + right) / 2可以改为left + (right - left) / 2
if (nums[target] > target)
right = middle;
else if (nums[target] < target)
left = middle;
else return middle;
}
return -1;
三、704 二分查找
力扣题目链接
将伪代码整理成C++代码即可,以下是我的运行代码
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 - left) / 2);
if (nums[middle] < target)
left = middle + 1;
else if (nums[middle] > target)
right = middle - 1;
else return middle;
}
return -1;
}
};
四、参考链接
1、视频链接:【手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找】
2、文章链接:代码随想录 | 704. 二分查找