我感觉还是得去复习以下数组,那下面几个篇章都是关于数组理论的,我简单介绍一下数组基础。
数组是存放在连续内存空间上的相同类型数据的集合。
数组可以方便的通过下标索引的方式获取到下标下对应的数据。
然后还有数组的特点就是
- 数组下标都是从0开始的。
- 数组内存空间的地址是连续的
那开始今天的题目:
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
逻辑很简单,就是找一个值而已,可以用暴力解法直接遍历,写一个for循环,然后开始遍历,在遍历的过程中。写个if条件语句判断是否满足题设条件,满足了直接返回下标即可。
但是这个方法的时间复杂度比较高,那就需要考虑更简单的写法 ,这个时候就该想到二分查找了。所谓二分查找就是靠区间中点值来进行比较,然后不断移动区间的左端点和右端点来找到目标值。
定义两个指针low和high,分别指向开始数组的两个端点,这个时候区间的中点值就是middle = (low + high)/2,不用担心取不尽,它最后会自己取整的。然后用中点值和目标值比较,如果中点值大于目标值,那就说明我们的右端点需要往下移动了,反之就是左端点需要往上移动,所以这个逻辑不是很复杂。
但是需要注意的是这个区间的闭合我们需要考虑清楚,左闭右闭还是左闭右开,不管哪一种都可以,但是我们需要都用这一种写法,两种写法的主要区别在于、for循环的那个判断条件。
如果是左闭右开的话那么就是while(low < high),注意这个时候是无法取到high的,if(nums[middle] > target) high 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以high更新为middle,即:下一个查询区间不会去比较nums[middle]。同时这里的初始化也就是右端点的定义是等于数组长度的,这刚好符合左闭右开区间
如果是左闭右闭区间就不一样了,由于可以取到右边端点的话,那么右边端点的定义就可以到数组的最后一个元素了。同时if(nums[middle] > target) high 也要更新为 middle-1,因为middle是已经比较过的,右端点可以取到,那么右端点就可以等于middle-1。
区间的定义就是不变量,那么在循环中坚持根据查找区间的定义来做边界处理,就是循环不变量规则。