给定一个数组,例如[7,8,9,0,1,2,3,4,5,6]
,是否可以确定旋转发生得比O(n)更快的索引?
使用O(n),只需遍历所有元素并将第一个递减元素标记为索引。
一个可能更好的解决方案是从两端向中间迭代,但这仍然是O(n)的最坏情况。
答案 0 :(得分:3)
(编辑:下面假设元素是不同的。如果它们不相同,我认为没有比扫描数组更好的了。)
您可以二进制搜索它。我不会发布任何代码,但这里是一般性的想法:(对于其余部分,我会假设a >= b
。如果a < b
,那么我们知道它仍处于排序顺序中)
取第一个元素,称之为a
,最后一个元素b
和中间元素,称之为c
。
如果a < c
,那么您知道枢轴位于c
和b
之间,您可以递归(使用c
和b
作为新的结束)。如果a > c
,那么您知道枢轴介于两者之间,并在那一半递归(以a
和c
作为结束)。
ADDENDUM:要扩展到包含重复的案例,如果我们有a = c > b
,那么我们会以c
和b
作为我们的结束,而如果a = c = b
,则我们会从a
进行扫描c
到d
以查看是否存在某些元素a
,使其不同。如果它不存在,则c
和c
之间的所有数字都相等,因此我们以b
和a > d < b
作为我们的结果递归。如果是,则有两种情况:
d
:此处a < d > b
是我们从左侧扫描后的最小元素,我们已经完成了。
d
:在这里,我们知道答案介于b
和O(log n)
之间,因此我们将这些作为我们的目标。
在最好的情况下,我们永远不必使用相等的情况,给我们O(n)
。最糟糕的情况是,这些扫描几乎包含所有阵列,给我们{{1}}。
答案 1 :(得分:2)
对于N个数组的数组,如果数组旋转最少1次且少于N次,我认为它可以正常工作:
int low=0, high = n-1;
int mid = (low +high)/2;
while( mid != low && mid != high)
{
if(a[low] < a[mid])
low = mid;
else
high = mid;
mid = (low + high)/2;
}
return high;
答案 2 :(得分:1)
您可以使用二进制搜索。如果您选择1作为中心值,则您知道中断是在前半部分,因为7&gt; 1&lt; 6。
答案 3 :(得分:0)
一个观察结果是,移位等于最小元素的索引。因此,您所要做的就是使用二进制搜索来查找最小元素。唯一的问题是,如果数组具有相同的元素,那么任务就会变得有点棘手:你无法获得比O(N)
时间更好的大O效率,因为你可以在[0, 0, 0, 0, ..., 100, 0, 0, 0, ..., 0]
之类的输入中获得当然,找到比线性更快的唯一非零元素。但是仍然以下算法达到O(Mins + Log(N))
,其中Mins
是最小元素的数量,如果array[0]
是最小值之一(否则Mins = 0
不给予惩罚)。
l = 0;
r = len(array) - 1;
while( l < r && array[l] == array[r] ) {
l = l + 1;
}
while( l < r ) {
m = (l + r) / 2;
if( array[m] > array[r] ) {
l = m + 1;
} else {
r = m;
}
}
// Here l is the answer: shifting the array l elements left will make it sorted
这适用于O(log N)
的唯一元素数组,O(N)
适用于非唯一元素数组(但仍然比大多数输入的天真解决方案更快)。
答案 4 :(得分:0)
前提条件
方法
所以任务是找到最小元素的索引。我们可以通过两种方式找到最低元素的索引
方法1 -
方法2
所以这可以像二进制搜索一样应用,在O(log(n))中我们可以找到最小元素的索引
答案 5 :(得分:0)
使用递归方法:
static void Main(string [] args) { var arr = new int [] {7,8,9,0,1,2,3,4,5,6}; Console.WriteLine(FindRotation(ARR)); }
private static int FindRotation(int[] arr)
{
var mid = arr.Length / 2;
return CheckRotation(arr, 0, mid, arr.Length-1);
}
private static int CheckRotation(int[] arr, int start, int mid, int end)
{
var returnVal = 0;
if (start < end && end - start > 1)
{
if (arr[start] > arr[mid])
{
returnVal = CheckRotation(arr, start, start + ((mid - start) / 2), mid);
}
else if (arr[end] < arr[mid])
{
returnVal = CheckRotation(arr, mid, mid + ((end - mid) / 2), end);
}
}
else
{
returnVal = end;
}
return returnVal;
}