我正在尝试解决一个经典的面试问题,这个问题基本上是在列表上进行二元搜索,然后首先增加然后减少。即使很明显我们可以实现 O(log n)我也无法弄清楚我写的下面的代码有什么问题:
#include <iostream>
using namespace std;
int binarySearch(int *A, int low, int high, int key)
{
while(low < high)
{
int mid = (low + high) / 2;
if(key < A[mid])
{
if(A[mid - 1] < A[mid] && A[mid] < A[mid + 1])
high = mid - 1;
else
low = mid + 1;
}
else if(key > A[mid])
{
if(A[mid - 1] < A[mid] && A[mid] < A[mid + 1])
low = mid + 1;
else
high = mid - 1;
}
else
return mid;
}
return -(low + 1);
}
int main()
{
const int SIZE = 8;
int A[SIZE] = {3,5,7,14,9,8,2,1};
cout<<binarySearch(A, 0, SIZE, 14);
return 0;
}
我问这个问题的原因是因为我想知道两件事。 1)有什么问题代码,因为它失败了一些值,如“14”。 2)可以改进吗?
答案 0 :(得分:6)
我认为你的代码不能很好地处理数组的增加和减少部分。
而不是告诉你具体如何做到这一点,这里有一些提示,我希望你能够完成它:)
一种解决方案是首先找到数组从O(logn)中的递增顺序到递减顺序的点,然后基于此,在O(logn)中执行特殊版本的二进制搜索。
如果你不知道怎么做,请告诉我,我会更多地解释我的答案。
答案 1 :(得分:2)
这是一个更完整的解决方案(仅作为参考)
一种解决方案是首先找到数组从O(logn)中的递增顺序到递减顺序的点,然后基于此,在O(logn)中执行特殊版本的二进制搜索。
第一部分可以通过查找array[i-1] <= array[i]
使用专门二进制搜索的最后一点来实现mid
索引移动条件是array[mid-1] <= array[mid]
而不是array[mid] <= target
示例代码
为了防止我成为一名面试黑客,下面仅介绍如何处理一个没有任何重复的数组。如有必要,代码将很快删除:
#include <stdio.h>
#include <stdlib.h>
int find_change_point(int array[], int low, int high, int array_size) {
int mid;
for (mid = (low + high) / 2; low <= high; mid = (low + high) / 2) {
// if true, it implies the point is on the higher side
if (array[mid - 1] <= array[mid]) {
if (mid == array_size - 1) {
return mid;
}
// since we already handles equality, only > is needed.
if (array[mid] > array[mid + 1]) {
return mid;
}
low = mid + 1;
} else {
// then simply imply the point is on the lower part
high = mid - 1;
}
}
return mid;
}
int main() {
const int SIZE_1 = 8;
int array_1[SIZE_1] = {3,5,7,14,9,8,2,1};
int change_point = find_change_point(array_1, 0, SIZE_1 - 1, SIZE_1);
printf("change_point_1 = %d\n", change_point);
const int SIZE_2 = 9;
int array_2[SIZE_2] = {3,5,7,14,15,16,17,19, 20};
change_point = find_change_point(array_2, 0, SIZE_2 - 1, SIZE_2);
printf("change_point_2 = %d\n", change_point);
const int SIZE_3 = 9;
int array_3[SIZE_3] = {9, 8, 7, 6, 5, 4, 3, 2, 1};
change_point = find_change_point(array_3, 0, SIZE_3 - 1, SIZE_3);
printf("change_point_3 = %d\n", change_point);
}
,输出为:
change_point_1 = 3
change_point_2 = 8
change_point_3 = 0
为了处理重复,您需要找到重复序列的左端和右端,并验证它们是增加还是减少序列。
第二部分有很多种。一个简单的解决方案是将它们视为两个数组,并对每个子数组执行一次二分查找以找到目标元素。
答案 2 :(得分:0)
对于你的代码我认为很多分支就像“if”操作一样。 以下是简单的伪代码供您参考:
while(1 < (high - low)){
int mid = (low + high) >> 1;
(key < A[mid]) ? high = mid : lo = mid;
}
return (key == A[lo]) ? lo : -1;
希望这可以帮到你。