cod*_*ict 161
这可以O(logN)
使用略微修改的二进制搜索来完成.
排序+旋转数组的有趣属性是,当您将其分成两半时,将始终对两半中的一半进行排序.
Let input array arr = [4,5,6,7,8,9,1,2,3]
number of elements = 9
mid index = (0+8)/2 = 4
[4,5,6,7,8,9,1,2,3]
^
left mid right
Run Code Online (Sandbox Code Playgroud)
因为看起来正确的子数组没有排序,而左子数组是排序的.
如果mid恰好是旋转点,则左右子阵列将被排序.
[6,7,8,9,1,2,3,4,5]
^
Run Code Online (Sandbox Code Playgroud)
但无论如何必须对一半(子阵列)进行排序.
通过比较每一半的开始和结束元素,我们可以很容易地知道哪一半是排序的.
一旦我们找到哪一半被分类,我们就可以看到该键是否存在于那一半 - 与极端的简单比较.
如果密钥出现在那一半中,我们递归调用该函数的那一半
,我们递归调用另一半的搜索.
我们在每个调用中丢弃一半的数组,这使得这个算法成为可能O(logN)
.
伪代码:
function search( arr[], key, low, high)
mid = (low + high) / 2
// key not present
if(low > high)
return -1
// key found
if(arr[mid] == key)
return mid
// if left half is sorted.
if(arr[low] <= arr[mid])
// if key is present in left half.
if (arr[low] <= key && arr[mid] >= key)
return search(arr,key,low,mid-1)
// if key is not present in left half..search right half.
else
return search(arr,key,mid+1,high)
end-if
// if right half is sorted.
else
// if key is present in right half.
if(arr[mid] <= key && arr[high] >= key)
return search(arr,key,mid+1,high)
// if key is not present in right half..search in left half.
else
return search(arr,key,low,mid-1)
end-if
end-if
end-function
Run Code Online (Sandbox Code Playgroud)
这里的关键是总是对一个子数组进行排序,使用它可以丢弃数组的一半.
Chu*_*cks 14
当数组中存在重复元素时,所选答案有错误.例如,arr = {2,3,2,2,2}
我们正在寻找3.然后,所选答案中的程序将返回-1而不是1.
这个面试问题在"破解编码面试"一书中有详细讨论.该书中特别讨论了重复元素的条件.由于op在评论中说数组元素可以是任何东西,我在下面给出我的解决方案作为伪代码:
function search( arr[], key, low, high)
if(low > high)
return -1
mid = (low + high) / 2
if(arr[mid] == key)
return mid
// if the left half is sorted.
if(arr[low] < arr[mid]) {
// if key is in the left half
if (arr[low] <= key && key <= arr[mid])
// search the left half
return search(arr,key,low,mid-1)
else
// search the right half
return search(arr,key,mid+1,high)
end-if
// if the right half is sorted.
else if(arr[mid] < arr[low])
// if the key is in the right half.
if(arr[mid] <= key && arr[high] >= key)
return search(arr,key,mid+1,high)
else
return search(arr,key,low,mid-1)
end-if
else if(arr[mid] == arr[low])
if(arr[mid] != arr[high])
// Then elements in left half must be identical.
// Because if not, then it's impossible to have either arr[mid] < arr[high] or arr[mid] > arr[high]
// Then we only need to search the right half.
return search(arr, mid+1, high, key)
else
// arr[low] = arr[mid] = arr[high], we have to search both halves.
result = search(arr, low, mid-1, key)
if(result == -1)
return search(arr, mid+1, high, key)
else
return result
end-if
end-function
Run Code Online (Sandbox Code Playgroud)
我的第一次尝试是使用二进制搜索找到应用的旋转次数 - 这可以通过使用通常的二进制搜索机制找到a [n]> a [n + 1]的索引n来完成.然后进行常规二进制搜索,同时旋转每个班次的所有索引.
int rotated_binary_search(int A[], int N, int key) {
int L = 0;
int R = N - 1;
while (L <= R) {
// Avoid overflow, same as M=(L+R)/2
int M = L + ((R - L) / 2);
if (A[M] == key) return M;
// the bottom half is sorted
if (A[L] <= A[M]) {
if (A[L] <= key && key < A[M])
R = M - 1;
else
L = M + 1;
}
// the upper half is sorted
else {
if (A[M] < key && key <= A[R])
L = M + 1;
else
R = M - 1;
}
}
return -1;
}
Run Code Online (Sandbox Code Playgroud)