数组
数组是存放在内存空间上的相同类型的数据集合
1) 数组的下标都从0开始
2) 数组元素内存空间的地址是连续的
3) 数组元素不能删除,只能覆盖,因为数组元素在内存空间的地址是连续的
4 ) 二维数组在内存的空间地址也是连续的
1. 二分法查找
关键问题:
-
确定while循环执行条件:left<right, left <= right, 还是其他
-
边界的更新条件,left = mid -1, 还是left = mid
解决方法:
- 定义有界区间为开区间?闭区间?还是左开右闭或者左闭右开
- 若有值区间为左闭右闭,显然left = right是有意义的,则while执行条件为left <= right;显然mid的索引值不为查找值,则边界更新为left = mid - 1, 或者 right = right +1
- 若有值区间为左闭右闭,显然left = right区间必然无查找值,甚至left = right - 1 时,两个端点不为查找值,中间也再无可查找值,所以执行条件可为right - left >1, 即left < right + 1; 显然mid的索引值不为查找值,边界的更新为 left = mid, mid = right
- 对于左开右闭与左闭右开,显然left = right区间必然无查找值,所以执行条件可为left < right + 1;对于边界的更新方式,区间开的一侧为 left = mid,或mid = right,区间闭的一侧left = mid - 1, 或者 right = right +1
运行结果:
- 对于左闭右闭的运行方式,查找成功时,mid = target索引值;查找不成功时,目标值介于nums[right]与nums[left]之间,且right = left +1。
- 对于左闭右开的运行方式,查找成功时,mid为目标值的索引;查找不成功时,目标值在nums[left=right]之前,进入最后一次循环时,
- 如果目标值介于[left, right),其中right=left+1,进入后,mid = left,由于left处的值小于目标值,left = mid + 1, 此时right = left,退出循环;
- 如果目标值在[left, right)之前,进入后,mid = left, left处的值大于目标值,所以right = mid,所以left=right,退出循环。
- 目标值不可能在[left, right)之后。
class Solution {
public:
int search(vector<int>& nums, int target) {
int start = 0;
int end = nums.size()-1;
if(nums[start]>target||nums[end]<target) return -1;
if(nums[start]==target) return start;
if(nums[end]==target) return end;
int mid;
for(int i = 0; i < nums.size(); i++){
if(start > end -1) return -1; //速度比if(start > end -1) return -1;更快
mid = (start + end) / 2;
if(nums[mid] == target) return mid;
if(nums[mid] < target) start = mid;
if(nums[mid] > target) end = mid;
}
return -1;
}
};
但是为使第一次计算与后面计算统一,对初始的边界条件不做事先判断时,只存在左闭右闭、与左闭右开两种情况,因为如果需要左开,则要事先判断索引0处的值是否为查找值;而右开的时候,只需要left = nums.size()+1
答案:
// 左闭右闭
class Solution {
public:
int search(vector<int>& nums, int target) {
int mid, left = 0, right= nums.size()-1;
while(left<=right){
mid = (left + right) / 2;
if(nums[mid] == target) return mid;
if(nums[mid] < target) left = mid + 1;
if(nums[mid] > target) right = mid - 1;
}
return -1;
}
};
//左闭右开
class Solution {
public:
int search(vector<int>& nums, int target) {
int mid, left = 0, right= nums.size();
while(left<right){
mid = (left + right) / 2;
if(nums[mid] == target) return mid;
if(nums[mid] < target) left = mid + 1;
if(nums[mid] > target) right = mid;
}
return -1;
}
};
时间复杂度 O(logn)???
空间复杂度 O(1)???