介绍
- 二分搜索的时间复杂度为O(logN)
- 使用场景:1、有序序列的查找;2、任意在二分以后可以淘汰一半的查找;3、有序循环数组查找
- 难点
1、由于二分过程中需要考虑的边界条件较多,循环终止调条件的设定,所以快速写出正确的代码比较困难。
2、题目变化情况多:1)处理或查找的对象不同:可能有序、可能无序。2)需要的判断条件不同:找等于x的数值所在位置、找大于等于x的数值所在位置。3) 需要返回的内容不同:返回等于x值的任意位置、最左位置、最右位置,返回等于x的值的个数 - 代码提示:划分过程中中间位置选择通常为:mid = (left + right) / 2,这种可能导致溢出,推荐的做法是:mid = left + (right - left) / 2。
经典题
- 给定无序数组arr,它的任意相邻位置不重复,请返回任意一个局部最小值出现的位置。
1、长度为0时返回-1(不存在)
2、长度为1时返回0
3、长度大于1时,1)先判断头和尾,如果0位置小于1位置或n位置小于n-1位置,则返回头或尾即可。2)如果不是1)中的情况那么可以得到2 ~ n - 1一定存在局部最小,然后考察它的中间位置,如果arr[mid]小于arr[mid - 1]和arr[mid + 1],那么它是局部最小,如果arr[mid]大于arr[mid - 1]和arr[mid + 1],左半部分或右半部分都存在局部最小,如果arr[mid]大于arr[mid - 1],那么左边一定存在局部最小,如果arr[mid]大于arr[mid + 1],那么右边一定存在局部最小 - 给定有序数组arr,找num最早出现的位置
用二分法查找num,同时用res记录num上一次出现的位置,如果接下来的查找中找到num就更新res - 给定有序循环数组arr,返回其中的最小值
有序循环数组:将有序数组左边任意长度放到数组的右边生成的新数组就是有序循环数组。
1、如果arr[left] < arr[right],那么该有序循环数组有序,arr[left]即为最小值
2、如果arr[left] >= arr[right],那么最小值出现在数组的中间,且左半部分大于右半部分,此时考察arr[mid],如果arr[mid] < arr[left]那么左半部分存在最小值,如果arr[mid] > arr[right]那么右半部分存在最小值,如果arr[left] <= arr[mid] <= arr[rigth],又arr[left] >= arr[right],此时arr[mid] = arr[left] = arr[right],这种情况只能通过遍历查找了。 - 给定不含重复元素的数组arr,请找出满足arr[i] = i的最左的位置,不存在则返回-1
1、考察首尾节点,如果arr[0] > n - 1,则返回-1,如果arr[n - 1] < 0,则返回-1
2、res初始化为-1,如果不满足1的条件,则考察arr[M],如果arr[M] > M,则右部分肯定不存在arr[i] = i,下一步在左半部分查找,如果arr[M] < M,则左半部分不存在arr[i] = i,下一步在右半部分查找,如果arr[M] = M则更新res,并继续在左半部分查找 - 给定完全二叉树的头节点,请返回节点数,如果二叉树节点数位n,请实现时间复杂度低于O(n)的算法。
以下方法时间复杂度为O(log(H2))
1、找到二叉树最左节点,在这个过程中可以得到树高
2、找根节点右子树的最左节点,如果该节点在整个数的最后一层,则该二叉树左子树为满二叉树,可求得节点数,此时应该递归解决右子树节点数的统计问题,如果该节点不能到达最后一层,则根节点的右子树为满二叉树,可求得节点数,此时应该递归解决左子树节点数的统计问题。 - 如何更快求整数k的n次方,请实现时间复杂度为O(logN)的算法
1、先将n化为二进制,假设有m比特,最高位不为0
2、依次求k2、k4、……、k2m - 1,这步的时间复杂度即为O(logN)
3、在n的二进制表示中,如果第i位不为0,则将k2i - 1累乘入结果中