我已经解决了这个问题好几天但仍然无法找到解决问题的方法。我的解决方案无法解决一些边缘情况
问题:
给定一个数组并按升序排序,用k个元素旋转数组,找到数组最小数的索引(原始非旋转数组的第一个元素)。例如:
1.给{3,4,1,3,3},返回2.
2.给{3,3,3,3,3},返回0.
3.给{1,1,4,1,1,1},返回3.
如果没有重复,可以使用二进制搜索在O(logn)时间内解决此问题,可以使用重复的二进制搜索,最坏情况时间复杂度为O(n)。
我的代码:
public int FindPivot(int[] array)
{
var i = 0;
var j = array.Length - 1;
while (i < j)
{
var mid = i + (j - i) / 2 + 1;
if (array[mid] < array[array.Length - 1])
{
j = mid - 1;
}
else if (array[mid] > array[array.Length - 1])
{
i = mid;
}
else
{
if (array[mid] == array[j])
{
j--;
}
if (array[mid] == array[i])
{
i++;
}
}
}
return i+1;
}
如果输入为{3,3,1,3,3,3,3,3},它不起作用,它返回3而正确的答案是2.因为在最后一步是i点索引2和j从索引3移动到索引2,它得到正确的元素但是i + 1使结果错误。我在这里缺少什么?
答案 0 :(得分:0)
我已经修改了您的代码,它似乎适用于所有情况。
我无法想到处理所有极端情况的任何好方法,因为你的原始代码混合了算法的概念而没有重复元素(分成两个子数组)和双指针算法有重复元素。
我想说的问题是移动两个指针的else
案例并未涵盖所有情况,例如您有可能会else
阻止array[i] < array[mid]
阻止i+1
因此我只是使用newbie's方法修改它:添加两个变量以跟踪我们找到的最小元素和最小索引。每当指针移动以覆盖所有可能的情况时更新它。最后返回索引。您无法执行返回k = 0
之类的操作,因为它无法处理{1,2,3,4}
完全没有轮换的情况(O(N)
)
修改后的代码是用C#编写的,我想从你的示例代码中读出来。
PS: 虽然平均而言,如果数据部分排序没有重复元素,这比O(N)
快,但最糟糕的情况是你提到的还是O(N)
。所以如果我是你,我会做一个简单的迭代,找到第一个最小元素......
同样来自此reference,using System;
public class Test
{
public static int FindPivot(int[] array)
{
var i = 0;
var j = array.Length - 1;
var ans = 1<<20;
var idx = 1<<20;
while (i < j)
{
var mid = i + (j - i) / 2 + 1;
// Console.WriteLine(String.Format("{0}, {1}, {2}", i, mid, j));
if (array[mid] < array[array.Length - 1])
{
if(array[mid] < ans || (array[mid] == ans && mid < idx)) { ans = array[mid]; idx = mid;}
j = mid - 1;
}
else if (array[mid] > array[array.Length - 1])
{
i = mid;
}
else
{
// Here did not consider case if array[i] < mid
if(array[j] < ans || (array[j] == ans && j < idx)) { ans = array[j]; idx = j;}
if(array[i] < ans || (array[i] == ans && i < idx)) { ans = array[i]; idx = i;}
if (array[mid] == array[j])
{
j--;
}
if (array[mid] == array[i])
{
i++;
}
}
}
if(array[j] < ans || (array[j] == ans && j < idx)) { ans = array[j]; idx = j;}
if(array[i] < ans || (array[i] == ans && i < idx)) { ans = array[i]; idx = i;}
Console.WriteLine("Minimum = " + ans);
return idx;
}
public static void Main()
{
int []a = {7,7,7,7,8,8,9,9,1,2,2,2,7,7};
int []b = {3,3,1,3,3,3,3,3};
int []c = {1,2,3,4};
int []d = {4,4,4,4};
int []e = {3,3,3,3,3,3,3,1,3};
int []f = {4,5,6,7,1,1,1,1};
Console.WriteLine(FindPivot(a));
Console.WriteLine(FindPivot(b));
Console.WriteLine(FindPivot(c));
Console.WriteLine(FindPivot(d));
Console.WriteLine(FindPivot(e));
Console.WriteLine(FindPivot(f));
}
}
是您可以达到的最佳元素。
sumIdosage
答案 1 :(得分:0)
根据@ shole的回答,我修改了一些代码以涵盖像{1,1,1,1,3,1,1,1,1,1,1,1,1这样的案例}。
public int FindPivot(int[] nums)
{
var i = 0;
var j = nums.Length - 1;
var ans = int.MaxValue;
var idx = int.MaxValue;
while (i < j)
{
var mid = i + (j - i) / 2 + 1;
if (nums[mid] < nums[nums.Length - 1])
{
if (nums[mid] < ans || (nums[mid] == ans && mid < idx)) { ans = nums[mid]; idx = mid; }
j = mid - 1;
}
else if (nums[mid] > nums[nums.Length - 1])
{
i = mid;
}
else
{
if (nums[j] < ans || (nums[j] == ans && j < idx)) { ans = nums[j]; idx = j; }
if (nums[mid] == nums[j])
{
j--;
}
if (nums[mid] == nums[i])
{
i++;
}
}
}
// Deal with cases like {1,1,1,1,1}
if (nums[i] == nums[nums.Length - 1] && nums[i] == nums[0] && i == j)
{
return 0;
}
if (nums[j] < ans || (nums[j] == ans && j < idx)) { ans = nums[j]; idx = j; }
return idx;
}