zoukankan      html  css  js  c++  java
  • 【编程题目】旋转数组中的最小元素☆

    69.旋转数组中的最小元素(数组、算法)。
    题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个
    排好序的数组的一个旋转,输出旋转数组的最小元素。
    例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为 1。

    我就用了最简单的方法。而且开始还没考虑1, 0, 1 ,1这样的情况

    /*
    69.旋转数组中的最小元素(数组、算法)。
    题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个
    排好序的数组的一个旋转,输出旋转数组的最小元素。
    例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为 1。
    start time 20:29
    end time 20:44
    */
    
    #include <stdio.h>
    
    int getMin(int * in, int len)
    {
        if (len == 1) //就一个数字
        {
            return in[0];
        }
        if (in[len - 1] > in[0]) //没有旋转 或最小数字多次出现
        {
            return in[0];
        }
        else
        {
            int min = in[0];
            for (int i = 1; i < len; i++)
            {
                if (in[i] < min)
                {
                    return in[i];
                }
            }
        }
    }
    
    void main()
    {
        int a[5] = {1,0,1,1,1};
        int min = getMin(a, 5);
        return;
    }

    看网上答案,发现可以用二分法。

    http://blog.csdn.net/xianliti/article/details/5647733 里解释的不错 考虑也很全面

    分析:这道题最直观的解法并不难。从头到尾遍历数组一次,就能找出最小的元素,时间复杂度显然是O(N)。但这个思路没有利用输入数组的特性,我们应该能找到更好的解法。

             我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的元素都大于或者等于后面子数组的元素。我们还可以注意到最小的元素刚好是这两个子数组的分界线。我们试着用二元查找法的思路在寻找这个最小的元素。

             首先我们用两个指针,分别指向数组的第一个元素和最后一个元素。按照题目旋转的规则,第一个元素应该是大于或者等于最后一个元素的(这其实不完全对,还有特例。后面再讨论特例)。

    接着我们得到处在数组中间的元素。如果该中间元素位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素。此时数组中最小的元素应该位于该中间元素的后面。我们可以把第一指针指向该中间元素,这样可以缩小寻找的范围。同样,如果中间元素位于后面的递增子数组,那么它应该小于或者等于第二个指针指向的元素。此时该数组中最小的元素应该位于该中间元素的前面。我们可以把第二个指针指向该中间元素,这样同样可以缩小寻找的范围。我们接着再用更新之后的两个指针,去得到和比较新的中间元素,循环下去。

    按照上述的思路,我们的第一个指针总是指向前面递增数组的元素,而第二个指针总是指向后面递增数组的元素。最后第一个指针将指向前面子数组的最后一个元素,而第二个指针会指向后面子数组的第一个元素。也就是它们最终会指向两个相邻的元素,而第二个指针指向的刚好是最小的元素。这就是循环结束的条件。

    分析的思路和我想的一样,画个图会好理解很多。原文代码不贴了,好像有几种情况的数据没处理好。

    这里需要考虑的几种情况有:

    1、输入的旋转数组就是没有经过旋转的排序数组,如:{1,2,3,4,5}

    2、中间指针指向的数 == 队头指针指向的数 == 队尾指针指向的数, 这个时候是无法判断中间指针是处于前面的递增子数组,还是后面的递增子数组。如:{1,0,1,1,1,1,1}

    3、还有就是数组元素全部相等的情况。如:{1,1,1,1,1,1}

    int foo42_v3(int *arr,int start, int end){
        int h = start;
        int t = end;
        int m;
    
        while(h<t){
            if(arr[h]<arr[t])
                return arr[h];
    
            m = (t-h+1)/2;
            if(arr[m]>arr[h]){
                h = m+1;
            }else if(arr[m]<arr[h]){
                t = m;
            }else{
                if(arr[m]==arr[t]){
                    h++;
                    t--;
                }else if(arr[m]<arr[t])
                    t = m;
                else
                    h = m+1;
            }
        }
    
        return arr[h];
    }
    
    int main(int argc, char* argv[])
    {
        int arr[6] = {1,1,1,1,1,1};
    
        printf("/n%d/n",foo42_v3(arr,0,5));
    
        getchar();
        return 0;
    }
  • 相关阅读:
    self 和 super 关键字
    NSString类
    函数和对象方法的区别
    求两个数是否互质及最大公约数
    TJU Problem 1644 Reverse Text
    TJU Problem 2520 Quicksum
    TJU Problem 2101 Bullseye
    TJU Problem 2548 Celebrity jeopardy
    poj 2586 Y2K Accounting Bug
    poj 2109 Power of Cryptography
  • 原文地址:https://www.cnblogs.com/dplearning/p/3922014.html
Copyright © 2011-2022 走看看