1. 程式人生 > >劍指offer:旋轉陣列的最小數字(Python)

劍指offer:旋轉陣列的最小數字(Python)

題目描述

把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。 輸入一個非遞減排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。 例如陣列{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該陣列的最小值為1。 NOTE:給出的所有元素都大於0,若陣列大小為0,請返回0。

解題思路

思路1

暴力解法:根據給定的陣列特點,從左到右遍歷陣列元素,當首次遇到陣列中某個元素比上一個元素小時,該元素就是我們需要的元素。

python程式碼

defminNumberInRotateArray(self, rotateArray):
    if not rotateArray:
        return
0 num = rotateArray[0] for i in range(1,len(rotateArray)): if rotateArray[i] >= num: num = rotateArray[i] else: return rotateArray[i]

思路2

思路1的做法太無腦,時間複雜度O(N)。旋轉陣列也算是一種排序陣列,可以用二分法解題,使時間複雜度最低控制在O(lgN)。
由於最近遞迴用的比較多,本能的就想通過遞迴求解該題。具體思路是用變數mid定位到陣列的中間位置,將陣列頭部的值與mid處的值進行比較,不斷縮小陣列。這裡有兩個需要注意的點:
1. 由於是旋轉陣列,縮小到最小的陣列大小為2,且陣列中第一個元素為陣列中值最大的元素,第二個元素是陣列中值最小的元素,最後返回第二個元素。
2. 當陣列中包含重複元素,具體到程式碼中是:當mid處的值等於陣列頭部的值時,無法判斷最小值位於mid左側還是右側,此時只能採取遍歷的方式。

Python程式碼

def minNumberInRotateArray(self, rotateArray):
    if not rotateArray:
        return 0
    if len(rotateArray)==2:
        return rotateArray[1]

    mid = int(len(rotateArray)/2)
    if rotateArray[mid] > rotateArray[0]:
        return self.minNumberInRotateArray(rotateArray[mid:])
    elif
rotateArray[mid] < rotateArray[0]: return self.minNumberInRotateArray(rotateArray[:mid+1]) else: for i in range(1,len(rotateArray)): if rotateArray[i] < rotateArray[0]: return rotateArray[i] return rotateArray[0]

思路3

思路3屬於思路2的小優化,可以縮短程式碼的長度,但不能改變程式碼的時間複雜度。具體來說,當mid處的值等於陣列頭部的值時,即當代碼需要遍歷時,可用一行程式碼代替for迴圈:

def minNumberInRotateArray(self, rotateArray):
    if not rotateArray:
        return 0
    if len(rotateArray)==2:
        return rotateArray[1]

    mid = int(len(rotateArray)/2)
    if rotateArray[mid] > rotateArray[0]:
        return self.minNumberInRotateArray(rotateArray[mid:])
    elif rotateArray[mid] < rotateArray[0]:
        return self.minNumberInRotateArray(rotateArray[:mid+1])
    else:
        return self.minNumberInRotateArray(rotateArray[1:])

思路4

由於每次遞迴都需要傳入陣列,這無疑更佔用儲存空間,特別當陣列特別長時。最後給出該方法的非遞迴版本,只有一個數組不變,變化的只有指向陣列的指標指向。

def minNumberInRotateArray(self, rotateArray):
    left = 0
    right = len(rotateArray)-1
    while left < right:
        mid = int((left+right)/2)
        if rotateArray[mid] > rotateArray[right]:
            left = mid+1
        elif rotateArray[mid] < rotateArray[right]:
            right = mid
        else:
            right -= 1
    return rotateArray[left]

雖然思路4程式碼簡短,時間複雜度和空間複雜度都比較低,但是如果稍微不注意,還是會掉到小坑裡,比如如果用mid處的值和陣列左邊的值比較,會有什麼不同;else語句中如果不讓right處的指向左移一位,而是讓left處的指標右移一位會怎麼樣,都是需要稍加留意的地方。