数组01_二分法

本文介绍了数组中的二分法查找,讨论了确定while循环执行条件和边界更新的关键问题,并提供了不同区间定义下的解决方案。二分查找的时间复杂度为O(logn),空间复杂度为O(1)。
摘要由CSDN通过智能技术生成

数组

数组是存放在内存空间上的相同类型的数据集合

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)???

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值