【问题标题】:Find minimum in sorted array, which was shifted在已移动的排序数组中找到最小值
【发布时间】:2015-08-24 11:41:32
【问题描述】:

面试题: 已排序的数组已旋转,因此元素可能以 3456712 的顺序出现。您将如何找到最小元素?您可以假设该数组具有所有唯一元素

需要实现修改后的二分查找算法。 C++中的第一个(不正确的解决方案):

int findMin(int a[], unsigned int leftIndex, unsigned int rightIndex)
{
    while(leftIndex <= rightIndex)
    {
        unsigned int mid = leftIndex + (rightIndex - leftIndex) / 2;
        if(leftIndex  == rightIndex) return a[rightIndex];
        if(a[rightIndex] > a[mid] && a[leftIndex] > a[mid]) 
        {
            ++leftIndex; 
            rightIndex = mid;
        }
        if(a[rightIndex] > a[mid]) rightIndex = --mid;
        if(a[rightIndex] < a[mid]) leftIndex = ++mid;
    }
}

在 Java 中的第二个实现是在排序数组中寻找最小值,该数组被移动了。它通过了单元测试。如果您在 Java 实现中发现错误,请告诉我。

class Test
{
    static public int findMin(int a[], int leftIndex, int rightIndex)
    {
        while(leftIndex <= rightIndex)
        {
            int mid = leftIndex + (rightIndex - leftIndex) / 2;

            if(leftIndex == rightIndex) return a[rightIndex];
            if(rightIndex - leftIndex == 1) return Math.min(a[leftIndex], a[rightIndex]);
            if(a[rightIndex] > a[mid]) rightIndex = mid;
            if(a[rightIndex] < a[mid]) leftIndex =  mid;
        }
        return -1;
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        int a1 [] = {1};
        System.out.println(findMin(a1,0,0));

        int a2 [] = {1,2};
        int a3 [] = {2, 1};
        System.out.println(findMin(a2,0,1));
        System.out.println(findMin(a3,0,1));

        int a4 [] = {1, 2, 3};
        int a5 [] = {2, 3, 1};
        int a6 [] = {3, 1, 2};
        System.out.println(findMin(a4,0,2));
        System.out.println(findMin(a5,0,2));
        System.out.println(findMin(a6,0,2));

        int a7 [] = {1, 2, 3, 4};
        int a8 [] = {2, 3, 4, 1};
        int a9 [] = {3, 4, 1, 2};
        int a10 [] = {4, 1, 2, 3};
        System.out.println(findMin(a7,0,3));
        System.out.println(findMin(a8,0,3));
        System.out.println(findMin(a9,0,3));
        System.out.println(findMin(a10,0,3));
    }
}

Java 中的递归实现:

static public int findMin(int a[], int leftIndex, int rightIndex)
    {
            int mid = leftIndex + (rightIndex - leftIndex) / 2;
            if(leftIndex == rightIndex) return a[rightIndex];
            if(rightIndex - leftIndex == 1) return Math.min(a[leftIndex], a[rightIndex]);
            if(a[rightIndex] > a[mid]) return findMin(a, leftIndex, mid);
            if(a[rightIndex] < a[mid]) return findMin(a, mid, rightIndex);
            return -1;
    }

【问题讨论】:

  • 我们在这里与同事共享代码,我们正在尝试检查 - 此实现是否正确。
  • 我已将您的评论添加到问题中 - 那些没有明确问题陈述的人可能在本网站上偏离主题。我还添加了一些标签 - 它们可以帮助专家找到您的问题 - 但我不确定您使用的语言。
  • 对于这种算法任务,测试驱动的方法往往效果很好。首先编写几个简单的测试,然后从那里开始工作。我发现测试驱动的方法可以帮助我提出诸如“我应该提供什么 API?”、“输入数组可以为空还是 null?”和“我是否应该使其通用以与任何元素类型或任何容器类型一起工作?”考虑到这是由面试问题引起的,提出这些考虑可以使候选人脱颖而出,因为它掌握了整体问题。

标签: c++ arrays binary-search


【解决方案1】:

没有。不幸的是,代码不正确。我做了一个简单的测试,程序没有返回(无限循环)。

我注意到的一些问题:

unsigned int mid = leftIndex + (leftIndex + rightIndex) / 2;

您想要介于两者之间。那你为什么要加leftIndex

然后

if(a[rightIndex] < a[mid]) leftIndex = ++mid;

为什么是++mid? 那么

if(a[rightIndex] > a[mid] && a[leftIndex] > a[mid]) 
        {
            ++leftIndex; 
            rightIndex = mid;
        }

我没有考虑清楚,但我认为这个案子不应该是一个单独的案子。 那么

if(a[rightIndex] > a[mid]) rightIndex = mid;

应该是&gt;= 而不仅仅是&gt;(考虑重复值)。

你要实现的大致思路是:

If leftIndex val is smaller than mid, then leftIndex=mid.
If rightIndex val is larger than mid, then rightIndex=mid.
When the indices meet (or are neighbours of each other) you found the min.

现在自己试试吧。只有当您自己没有正确理解时,您才应该继续阅读。

我稍微修改了您的代码以使其正常工作:

int findMin(int a[], unsigned int leftIndex, unsigned int rightIndex)
{
    if(a[leftIndex] < a[rightIndex]){
      //then the array is perfectly sorted (i.e. shifted k*size_of_array for any integer k) 
      //hence we return the first element.
      return a[leftIndex];
    }
    while(leftIndex <= rightIndex)
    {
        unsigned int mid = leftIndex + (rightIndex - leftIndex) / 2;
        if((leftIndex  == rightIndex) || (leftIndex+1 == rightIndex))
        {
         return a[rightIndex];
        }
        if(a[leftIndex] <= a[mid]) leftIndex = mid;
        if(a[rightIndex] >= a[mid]) rightIndex = mid;
    }
}

注意 1:我还没有完全测试过这段代码。所以它可能不是防弹的。但它适用于一些简单的例子。当我有更多时间时,我可能会测试一些极端情况。

注 2:可以进一步清理代码。但我还是想靠近你的sn-p。

【讨论】:

    猜你喜欢
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 2020-11-28
    • 2018-05-14
    相关资源
    最近更新 更多