在具有重复元素的已排序和旋转数组中查找最小数量

时间:2017-06-29 22:52:06

标签: algorithm binary-search

我已经解决了这个问题好几天但仍然无法找到解决问题的方法。我的解决方案无法解决一些边缘情况 问题:
给定一个数组并按升序排序,用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使结果错误。我在这里缺少什么?

2 个答案:

答案 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)。所以如果我是你,我会做一个简单的迭代,找到第一个最小元素......

同样来自此referenceusing 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)); } } 是您可以达到的最佳元素。

http://ideone.com/v3KVwu

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;
    }