本文正在参与掘金团队号上线活动,点击 查看大厂春招职位
一、题目描述:
- 进阶:你可以设计一个时间复杂度为 O(log n) 的解决方案吗?
二、思路分析:
暴力解法
直接遍历一遍数组,查看是否出现目标元素。无法完成O(log n)的要求。
- 时间复杂度:O(N),这里 N 是数组的长度。
- 空间复杂度:O(1),使用到的临时变量的个数是常数。
二分
参考题解
没想到吧,数组不是严格的单调增或者单调减也可以使用二分查找。 二分的话我们需要找到一个mid位置。判断mid位置和目标元素的大小关系。 但是这道题我们需要根据mid的位置,判断mid位置的值和右边界的大小关系。
三、AC 代码:
function search($nums, $target) {
$len_n = count($nums);
$left = 0;
$right = $len_n - 1;
while ($left < $right) {
//加1是因为下面的判断有left=mid的情况,为了避免死循环
$mid = $left + (int)(($right - $left + 1) / 2);
//此时对应第三种情况,我们选择判断mid右边的区间是否包含target
if ($nums[$mid] < $nums[$right]) {
if ($target >= $nums[$mid] && $target <= $nums[$right]) {
$left = $mid;
} else {
$right = $mid - 1;
}
} else {
//这对应着上图中1,2,3情况。我们选择判断mid左边的区间是否包含target的情况
if ($target >= $nums[$left] && $target <= $nums[$mid - 1]) {
$right = $mid - 1;
} else {
$left = $mid;
}
}
}
//最后循环结束的时候是left==right,所以还需要判断一下最后一个元素是否是target元素。
return $nums[$left] == $target ? $left : -1;
}
四、总结:
大家都说,写二分,细节是魔鬼。建议看一下上面的引用题解里提到的博主的二分题解合辑。里面有怎么处理各种边界情况,怎么判断等~