zoukankan      html  css  js  c++  java
  • 42.旋转数组的最小元素[Get min value of rotated array]

    【题目】

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

    【分析】

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

    我们容易想到二分查找,其时间复杂度为O(logn)。这个问题是否可以运用二分查找呢?答案是肯定的。观察一下数组的特性,首先递增(称为递增a),然后突然下降到最小值,然后再递增(称为递增b)。

    对于一般的情况,假设A为输入数组,left 和 right 为数组左右边界的坐标,考察中间位置的值A[mid] 。

    (1)如果A[mid] >= A[left],表明处于递增a,因此调整left = mid。

    (2)如果A[mid] <= A[right],表明处于递增b,调整right = mid。

    经过若干次调整以后,left指向递增a的最后一个元素,right指向递增b的第一个元素;此时left和right相邻,即right-left==1,那么较小的一个A[right]就是数组的最小值。

    但是还有特殊情况需要考虑:

    (3)旋转元素个数为0,即旋转数组本身就是递增序列。即A[left]<A[right],那么A[left]就是最小值。

    (4)如果A[left]== A[mid]== A[right],若果仍然按照(1)(2)的做法,那么最终left和right会指向同一个元素,即left=right,而无法跳出循环,此时就要使用常规方法求解。

    举几个具体例子就清楚了:

    {3, 4, 5, 1, 2},A[mid] >A[left]> A[right],最终left==right-1,最小值为1;符合(1,2)。

    {3, 4, 5, 1, 3},A[mid] >A[left]=A[right],最终left==right-1,最小值为1;符合(1,2)。

    {3, 3, 3, 1,2},A[mid]=A[left]>A[right],最终left==right-1,最小值为1;符合(1,2)。

    {3, 3, 3, 1,3},A[mid]=A[left]=A[right],常规方法求解,最小值为1;符合(4)。

    {1, 2, 3, 4, 5},A[left]<A[right],最小值为1;符合(3)。

    【代码】

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
     

    // 42_GetRotationArrayMinValue.cpp : Defines the entry point for the console application.
    //

    #include "stdafx.h"
    #include <iostream>
    using namespace std;

    // Get min value from data[left] to data[right]
    int MinInOrder(int *data, int left, int right)
    {
        
    int minValue = data[left];
        
    for (int i = left + 1; i < right; ++i)
        {
            
    if (data[i] < minValue)
                minValue = data[i];
        }
        
    return minValue;
    }
    /*
    get min value of rotation array
    {3, 4, 5, 1, 2},A[mid] >A[left]> A[right],left==right-1,min=A[right]=1。
    {3, 4, 5, 1, 3},A[mid] >A[left]=A[right],left==right-1,min=A[right]=1。
    {3, 3, 3, 1,2},A[mid]=A[left]>A[right],left==right-1,min=A[right]=1。
    ***{3, 3, 3, 1,3},A[mid]=A[left]=A[right],use normal function to get min=1。
    ***{1, 2, 3, 4, 5},A[left]<A[right],min=A[left]=1。
    */

    int GetRotationArrayMinValue(int *A, int n)
    {
        
    if(NULL == A || n < 0)
            
    throw new std::exception("Invalid params!");
        
    int left = 0;
        
    int right = n - 1;
        
    if (A[left] < A[right])
            
    return A[left];
        
    while(A[left] >= A[right])
        {
            
    // final break out here
            if (right - left == 1)
                
    return A[right];

            
    int mid = (left + right) / 2;

            
    // special case
            // process A[mid]=A[left]=A[right]
            if (A[left] == A[mid] && A[mid] == A[right])
            {
                
    return MinInOrder(A, left, right);
            }

            
    // normal cases
            if (A[mid] >= A[left])
                left = mid;
            
    else if (A[mid] <= A[right])
                right = mid;
        }
    }

    void test_base(int *data, int n)
    {
        
    int result = GetRotationArrayMinValue(data, n);
        cout << result << endl;
    }

    void test_case1()
    {
        
    int data[] = {34512};
        
    int length = sizeof(data) / sizeof(int);
        test_base(data, length);
    }

    void test_case2()
    {
        
    int data[] = {34513};
        
    int length = sizeof(data) / sizeof(int);
        test_base(data, length);
    }
    void test_case3()
    {
        
    int data[] = {33312};
        
    int length = sizeof(data) / sizeof(int);
        test_base(data, length);
    }
    void test_case4()
    {
        
    int data[] = {33313};
        
    int length = sizeof(data) / sizeof(int);
        test_base(data, length);
    }
    void test_case5()
    {
        
    int data[] = {12345};
        
    int length = sizeof(data) / sizeof(int);
        test_base(data, length);
    }

    void test_main()
    {
        test_case1();
        test_case2();
        test_case3();
        test_case4();
        test_case5();
    }

    int _tmain(int argc, _TCHAR *argv[])
    {
        test_main();
        
    return 0;
    }

    最后总结一下本面试题的主要考点:

    1. 考查对二分查找的理解。本题变换了二分查找的条件,输入数组不是排序的,而是排序数组的一个旋转。这要求我们对二分查找的过程有深刻的理解。

    2. 考查沟通学习能力。如果在面试过程中,面试官提出新的概念,比如“数组的旋转”,我们要主动和面试官沟通,多问几个问题把概念弄清楚。

    3. 考查思维的全面性。比如要考虑到:(1)排序数组本身是数组旋转的一个特例;(2)要考虑到数组中有相同数字的特例。如果不能很好处理这些特例,就很难写出让面试官满意的完美代码。

    【参考】

    http://zhedahht.blog.163.com/blog/static/25411174200952765120546/

    http://zhuyanfeng.com/archives/2923

    http://blog.csdn.net/wuzhekai1985/article/details/6733700

    个人学习笔记,欢迎拍砖!---by hellogiser

    Author: hellogiser
    Warning: 本文版权归作者和博客园共有,欢迎转载,但请保留此段声明,且在文章页面明显位置给出原文连接。Thanks!
    Me: 如果觉得本文对你有帮助的话,那么【推荐】给大家吧,希望今后能够为大家带来更好的技术文章!敬请【关注】
  • 相关阅读:
    很长的下拉框菜单
    Pure CSS Buttons – Good Button Style and No Images
    ssh 配置
    php大量session存储到内存中,散列及过期回收
    array_append_distinct, array_erase函数
    关于C# 中的Attribute 特性(转载)
    Jquery如何操作Table的某一个td
    ASP.NET应用程序生命周期趣谈(四) HttpHandler和页面生命周期
    ASP.NET应用程序生命周期趣谈(五) IIS7瞎说
    ASP.NET应用程序生命周期趣谈(三)
  • 原文地址:https://www.cnblogs.com/hellogiser/p/3740681.html
Copyright © 2011-2022 走看看