写在前面:本文侧重诠释对算法的思考记录过程,忽略其他诸如代码简洁、字符编码等细节问题。
<?php
//二分查找,针对的是一个有序的数据集合,每次都通过跟区间的中间元素对比,
//将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0为止。
//时间复杂度:O(logn)
function divide_two_select($nums, $target) {
if (count($nums) <= 1) {
return 0;
}
return divide_select($nums, $target, 0, count($nums)-1);
}
function divide_select($nums, $target, $start, $end) {
if ($start > $end) {
return -1;
}
$middle = floor(($start + $end) / 2);
if ($target < $nums[$middle]) {
return divide_select($nums, $target, $start, $middle-1);
} elseif ($target > $nums[$middle]) {
return divide_select($nums, $target, $middle+1, $end);
} else {
return $middle;
}
}
//二分法查找的变形版本:在一个给定排序序列中查找第一个等于给定值的元素
//(待查找的元素在序列中有多个)
function divide_two_select_first($nums, $target) {
if (count($nums) <= 1) {
return 0;
}
return divide_select_first($nums, $target, 0, count($nums)-1);
}
function divide_select_first($nums, $target, $start, $end) {
if ($start > $end) {
return -1;
}
$middle = floor(($start + $end) / 2);
if ($target < $nums[$middle]) {
return divide_select_first($nums, $target, $start, $middle-1);
} elseif ($target > $nums[$middle]) {
return divide_select_first($nums, $target, $middle+1, $end);
} else {
if ($middle==0 || ($nums[$middle-1] != $target)) {
return $middle;
} else {
return divide_select_first($nums, $target, $start, $middle-1);
}
}
}
//二分法查找的变形版本:在给定已排序序列中查找最后一个等于给定值的元素
//(待查找的元素在序列中有多个)
function divide_two_select_last($nums, $target) {
if (count($nums) <= 1) {
return 0;
}
return divide_select_last($nums, $target, 0, count($nums)-1);
}
function divide_select_last($nums, $target, $start, $end) {
if ($start > $end) {
return -1;
}
$middle = floor(($start + $end) / 2);
if ($target < $nums[$middle]) {
return divide_select_last($nums, $target, $start, $middle-1);
} elseif ($target > $nums[$middle]) {
return divide_select_last($nums, $target, $middle+1, $end);
} else {
if ($middle==count($nums)-1 || ($nums[$middle+1] != $target)) {
return $middle;
} else {
return divide_select_last($nums, $target, $middle+1, $end);
}
}
}
//二分法查找的变形版本:在给定排序序列中查找第一个大于等于给定值的元素
function divide_two_select_large_first($nums, $target) {
if (count($nums) <= 1) {
return 0;
}
return divide_select_large_first($nums, $target, 0, count($nums)-1);
}
function divide_select_large_first($nums, $target, $start, $end) {
if ($start > $end) {
return -1;
}
$middle = floor(($start + $end) / 2);
if ($target <= $nums[$middle]) {
if ($middle==0 || $nums[$middle-1] < $target) {
return $middle;
} else {
return divide_select_large_first($nums, $target, $start, $middle-1);
}
} elseif ($target > $nums[$middle]) {
return divide_select_large_first($nums, $target, $middle+1, $end);
}
}
//二分法查找的变形版本:在给定序列中查找最后一个小于等于给定值的元素
function divide_two_select_small_last($nums, $target) {
if (count($nums) <= 1) {
return 0;
}
return divide_select_small_last($nums, $target, 0, count($nums)-1);
}
function divide_select_small_last($nums, $target, $start, $end) {
if ($start > $end) {
return -1;
}
$middle = floor(($start + $end) / 2);
if ($target < $nums[$middle]) {
return divide_select_small_last($nums, $target, $start, $middle-1);
} elseif ($target >= $nums[$middle]) {
if ($middle==count($nums)-1 || $nums[$middle+1] > $target) {
return $middle;
} else {
return divide_select_small_last($nums, $target, $middle+1, $end);
}
}
}
参考来源:https://xueyuanjun.com/books/data-structure-and-algorithms