用于在排序和旋转数组中搜索元素的 PHP 程序
通过二进制搜索,可以在 O(log n) 时间内找到排序数组中的元素。但是假设我们在你事先不知道的某个枢轴上旋转一个升序排序的数组。因此,例如,1 2 3 4 5 可能会变成 3 4 5 1 2。设计一种方法来在 O(log n) 时间内找到旋转数组中的元素。
例子:
Input : arr[] = {5, 6, 7, 8, 9, 10, 1, 2, 3};
key = 3
Output : Found at index 8
Input : arr[] = {5, 6, 7, 8, 9, 10, 1, 2, 3};
key = 30
Output : Not found
Input : arr[] = {30, 40, 50, 10, 20}
key = 10
Output : Found at index 3
此处提供的所有解决方案都假定数组中的所有元素都是不同的。
基本解决方案:
方法:
- 这个想法是找到枢轴点,将数组分成两个子数组并执行二进制搜索。
- 寻找枢轴的主要思想是——对于一个排序(按递增顺序)和枢轴数组,枢轴元素是唯一一个其下一个元素小于它的元素。
- 使用上面的语句和二分查找可以找到pivot。
- 找到主元后,将数组分成两个子数组。
- 现在对各个子数组进行排序,以便可以使用二进制搜索来搜索元素。
执行:
Input arr[] = {3, 4, 5, 1, 2}
Element to Search = 1
1) Find out pivot point and divide the array in two
sub-arrays. (pivot = 2) /*Index of 5*/
2) Now call binary search for one of the two sub-arrays.
(a) If element is greater than 0th element then
search in left array
(b) Else Search in right array
(1 will go in else as 1 < 0th element(3))
3) If element is found in selected sub-array then return index
Else return -1.
下面是上述方法的实现:
PHP
$arr[$mid])
return binarySearch($arr, ($mid + 1),
$high, $key);
else
return binarySearch($arr, $low,
($mid -1), $key);
}
// Function to get pivot.
// For array 3, 4, 5, 6, 1, 2
// it returns 3 (index of 6)
function findPivot($arr, $low, $high)
{
// base cases
if ($high < $low)
return -1;
if ($high == $low)
return $low;
/*low + (high - low)/2;*/
$mid = ($low + $high)/2;
if ($mid < $high and $arr[$mid] >
$arr[$mid + 1])
return $mid;
if ($mid > $low and $arr[$mid] <
$arr[$mid - 1])
return ($mid - 1);
if ($arr[$low] >= $arr[$mid])
return findPivot($arr, $low,
$mid - 1);
return findPivot($arr, $mid + 1, $high);
}
// Searches an element key
// in a pivoted sorted array
// arr[] of size n */
function pivotedBinarySearch($arr, $n, $key)
{
$pivot = findPivot($arr, 0, $n - 1);
// If we didn't find a pivot,
// then array is not rotated
// at all
if ($pivot == -1)
return binarySearch($arr, 0,
$n - 1, $key);
// If we found a pivot,
// then first compare
// with pivot and then
// search in two subarrays
// around pivot
if ($arr[$pivot] == $key)
return $pivot;
if ($arr[0] <= $key)
return binarySearch($arr, 0,
$pivot - 1, $key);
return binarySearch($arr, $pivot + 1,
$n - 1, $key);
}
// Driver Code
// Let us search 3
// in below array
$arr1 = array(5, 6, 7, 8, 9, 10, 1, 2, 3);
$n = count($arr1);
$key = 3;
// Function calling
echo "Index of the element is : ",
pivotedBinarySearch($arr1, $n, $key);
// This code is contributed by anuj_67.
?>
PHP
$h) return -1;
$mid = ($l + $h) / 2;
if ($arr[$mid] == $key)
return $mid;
/* If arr[l...mid] is sorted */
if ($arr[$l] <= $arr[$mid])
{
/* As this subarray is
sorted, we can quickly
check if key lies in
half or other half */
if ($key >= $arr[$l] &&
$key <= $arr[$mid])
return search($arr, $l,
$mid - 1, $key);
return search($arr, $mid + 1,
$h, $key);
}
/* If arr[l..mid] is not
sorted, then arr[mid... r]
must be sorted*/
if ($key >= $arr[$mid] &&
$key <= $arr[$h])
return search($arr, $mid + 1,
$h, $key);
return search($arr, $l,
$mid-1, $key);
}
// Driver Code
$arr = array(4, 5, 6, 7, 8, 9, 1, 2, 3);
$n = sizeof($arr);
$key = 6;
$i = search($arr, 0, $n-1, $key);
if ($i != -1)
echo "Index: ", floor($i), "
";
else
echo "Key not found";
// This code is contributed by ajit
?>
输出:
Index of the element is : 8
复杂性分析:
- 时间复杂度: O(log n)。
二进制搜索需要进行 log n 次比较才能找到元素。所以时间复杂度是O(log n)。 - 空间复杂度: O(1),不需要额外的空间。
感谢 Ajay Mishra 的初步解决方案。
改进的解决方案:
方法:而不是两次或多次二分搜索,结果可以在一次二分搜索中找到。需要修改二进制搜索以执行搜索。这个想法是创建一个递归函数,将 l 和 r 作为输入范围和键。
1) Find middle point mid = (l + h)/2
2) If key is present at middle point, return mid.
3) Else If arr[l..mid] is sorted
a) If key to be searched lies in range from arr[l]
to arr[mid], recur for arr[l..mid].
b) Else recur for arr[mid+1..h]
4) Else (arr[mid+1..h] must be sorted)
a) If key to be searched lies in range from arr[mid+1]
to arr[h], recur for arr[mid+1..h].
b) Else recur for arr[l..mid]
下面是上述想法的实现:
PHP
$h) return -1;
$mid = ($l + $h) / 2;
if ($arr[$mid] == $key)
return $mid;
/* If arr[l...mid] is sorted */
if ($arr[$l] <= $arr[$mid])
{
/* As this subarray is
sorted, we can quickly
check if key lies in
half or other half */
if ($key >= $arr[$l] &&
$key <= $arr[$mid])
return search($arr, $l,
$mid - 1, $key);
return search($arr, $mid + 1,
$h, $key);
}
/* If arr[l..mid] is not
sorted, then arr[mid... r]
must be sorted*/
if ($key >= $arr[$mid] &&
$key <= $arr[$h])
return search($arr, $mid + 1,
$h, $key);
return search($arr, $l,
$mid-1, $key);
}
// Driver Code
$arr = array(4, 5, 6, 7, 8, 9, 1, 2, 3);
$n = sizeof($arr);
$key = 6;
$i = search($arr, 0, $n-1, $key);
if ($i != -1)
echo "Index: ", floor($i), "
";
else
echo "Key not found";
// This code is contributed by ajit
?>
输出:
Index: 2
复杂性分析:
- 时间复杂度: O(log n)。
二进制搜索需要进行 log n 次比较才能找到元素。所以时间复杂度是O(log n)。 - 空间复杂度: O(1)。
因为不需要额外的空间。
感谢 Gaurav Ahirwar 提出上述解决方案。
如何处理重复?
在允许重复的所有情况下,看起来都不可能在 O(Logn) 时间内进行搜索。例如考虑在 {2, 2, 2, 2, 2, 2, 2, 2, 0, 2} 和 {2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2 , 2}。
看起来不可能通过在中间进行恒定数量的比较来决定是在左半部分还是右半部分重复。
类似文章:
- 查找已排序和旋转数组中的最小元素
- 给定一个排序和旋转的数组,查找是否存在具有给定总和的对。
有关详细信息,请参阅有关在排序和旋转数组中搜索元素的完整文章!