Day1 数组part1
一、二分法
原理比较简单,高中知识——每次选取区间中间值,与目标值比较,依据比较结果更新区间边界,不断往复,最终得到目标值。
需要特别强调的是,二分法针对的数组必须是有序的!数组必须有序!
由于每次将数组长度折半,因此时间复杂度是O(logn),在长数组中查找具体的数值速度会很快。
对应题目参见Leetcode-704
在实际编写代码时,需要注意:
每次二分结束之后的子数组,需要在抽象的形式上和最开始的定义一致,以保证在while
循环中的循环不变量,从而保证边界条件的准确判断,避免死循环。
具体而言,如果开始输入的数组是左闭右闭,那么每次更新之后,新的子数组区间边界也要保证左闭右闭,左闭右开亦然。
反映在代码上,左闭右闭需要在
- 开始时将右指针指向数组最右侧变量
left, right = 0, len(nums)-1
- 循环终止条件为
left< =right
,这是因为对于左闭右闭区间,左右边界相等是有意义的,此时只有一个数 - 在更新区间边界时,需要保证左闭右闭的一致性,即
left = mid + 1 right = mid -1
这样就保证:不管是对于原始输入,还是二分之后的子数组,在抽象形式上他们保持一致,均为左闭右闭,因此循环终止条件不会造成死循环。
此外,对于二分法,很多题目考察算法的终止状态。
步进debug推演就可以发现:左闭右闭算法最终状态是left和right指针重合,之后二者错开,跳出循环。
宏观上,两个指针在不断逼近目标数字,因此如果目标数字小于数组中的所有元素,那么终止状态是left和right指针重合的指向最左侧的最小元素,之后错开。
二、移除数组中的指定元素
直接的暴力想法是开辟新的空间,遍历所有数组元素,将非指定元素移动到新开辟的空间中
这是很自然的想法
但是如果要求不开辟新的存储空间,即原地的移除指定元素,这就需要使用双指针
原理也很好理解→fast指针遍历数组中的元素,看每次拿到的数是否等于 val
,slow指针新数值的候选填充位置(待填充位置),将fast需要移动的数字(非移除数字),直接覆盖到slow的位置上,遇到需要移除的数字,fast向后移动,slow保持
对应题目参见Leetcode-27