面試題8:旋轉數組的最小數字


題目:把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個遞增的排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如輸入{1,2,3,4,5}的一個旋轉為{3,4,5,1,2},該數組的最小值為1。

分析

最直觀的想法就是順序遍歷一次數組,就能夠找出最小的數字,這樣的時間復雜度是O(n),當時我也是這么跟面試官說的,我說遍歷一次不就OK了嗎?面試官說“如果你覺得遍歷一次是你覺得最好的,那就跟我說!”我立馬說不是的,讓我想想,應該還有其他更有的方法。是的,既然叫做旋轉數組,那么我們就需要利用好旋轉數組的特性。看到這樣的旋轉數組查找最小數,我們會不會潛意識里面就想到了二分查找呢。確實,這道題目就是用二分查找的思路來解決,中間用到了旋轉數組的一些特性。以題目中的旋轉數組為例,{3,4,5,1,2},我們可以有序數組經過旋轉以后被分割為兩段有序的數組,比如此處被分為{3,4,5}{1,2}這樣連個數組,並前前半段數組中的數字肯定大於等於后半段的數組。我們找中間元素,讓其跟元素首元素比較,如果大於首元素,則中間元素屬於前半段有序數組,如果小於尾元素,那么中間元素就是后半段的元素。

這里我們設定兩個指針start和end分別指向數組的首尾元素,然后當start指向前半段最后一個元素,end指向后半段第一個元素,這是程序就找到了數組中的最小元素,就是end指向的那個數,程序的出口就是 end-start==1。

下面的代碼示例中寫了兩個方法,第一個方法是返回最小元素在數組中的位置,如果輸入錯誤則返回-1;第二個方法是直接返回數組中的最小元素。

代碼實例

View Code
#include<iostream>
#include<stdlib.h>
#include<stack>
using namespace std;

int min(int arry[],int len)//返回最小數的坐標
{
    if(arry==NULL||len<=0)
        return -1;

    int start=0;
    int end=len-1;
    while(start<end)
    {
        //如果首個元素小於最后一個元素,表明數組是排序的。
        if(arry[start]<arry[end])
            return start;

        //當start指針和end指針隔壁的時候,返回end指針就是最小元素的坐標
        if(end-start==1)
            return end;
        int mid=(start+end)/2;
        //如果arry[mid],arry[start]和arry[end]三個數相等,就只能使用順序查找
        if(arry[mid]==arry[start]&&arry[mid]==arry[end])
        {
            int index=start;
            for(int i=start+1;i<=end;i++)
            {
                if(arry[i]<arry[index])
                    index=i;
            }
            return index;
        }

        //如果中間元素小於末尾元素,那么表明中間元素在后半段數組中,修改end指針
        if(arry[mid]<arry[end])
        {
            end=mid;
        }
        //如果中間元素大於首元素,那么表明中間元素在前半段數組中,修改start指針
        else if(arry[mid]>arry[start])
        {
            start=mid;
        }
    }
    return -1;
}

int minNum(int arry[],int len)//返回最小數的值
{
    if(arry==NULL||len<=0)
        throw exception("非法輸入");

    int start=0;
    int end=len-1;
    while(arry[start]>=arry[end])
    {
        if(end-start==1)//如果start和end相差1則返回arry[end]
            return arry[end];

        int mid=(start+end)/2;
        //如果arry[mid],arry[start]和arry[end]三個數相等,就只能使用順序查找
        if(arry[mid]==arry[start]&&arry[mid]==arry[end])
        {
            int result=arry[start];
            for(int i=start+1;i<=end;i++)
            {
                if(arry[i]<result)
                    result=arry[i];
            }
            return result;
        }

        if(arry[mid]>=arry[start])//如果中間元素大於首元素,則移動首指針
        {
            start=mid;
        }
        else if(arry[mid]<=arry[end])
        {
            end=mid;
        }
    }
    return arry[start];//如果一開始arry[start]<arry[end]表明數組是排序數組,返回arry[start]
}

void main()
{
    int arry[]={1,0,1,1,1};
    int len=sizeof(arry)/sizeof(int);

    int index=min(arry,len);
    int minnum=minNum(arry,len);

    cout<<"最小數在數組中的位置:"<<index<<endl;
    cout<<"最小數的值:"<<minnum<<endl;

    system("pause");
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM