數組是最簡單的一種數據結構。我們經常碰到的一個基本問題,就是尋找整個數組中最大的數,或者最小的數。這時,我們都會掃描一遍數組,把最大(最小)的數找出來。如果我們需要同時找出最大和最小的數呢?
對於一個由N個整數組成的數組,需要比較多少次才能把最大和最小的數找出來呢?
這個題目比價簡單,主要方案如下:
方案一:分別求最大和最小值。這是一種比較常規的解法。可以分別求出數組的最大值和最小值,這樣,我們可以采用最基本的冒泡思想遍歷兩次(2N)就能求解。
方案二:分組求解。由於前面的需要遍歷2N次。這裡為了使其遍歷的次數減少,我們可以采用分組。
(1) 按順序將數組中相鄰的兩個數分在同一組,邏輯上分組,實際什麼都不用做;
(2) 比較同一組的兩個數,將大的數放在偶數位上,小的放在奇數位上;
(3) 最後,從偶數位上求最大值,奇數位上求最小值即可。
這樣一共需要比較1.5N次。這種辦法雖然比較次數變少了,但卻破壞了原數組,因為我們交換了數組數據的位置。
方案三:改進的分組。此種方法可以避免破壞原數據的順序。
(1) 用兩個變量max和min分別存儲當前的最大值和最小值。
(2) 同一組的兩個數比較完之後,不再調整順序,將其中較大的與當前max比較,較小的與min比較;
(3) 如此反復,直到遍歷完整個數組。
整個過程比較次數也為1.5N次,但是沒有對原數據進行更改,如果數據是在只讀存儲區,那麼該方法就能派上用場了。
方案四:分治策略。該方法用到歸並排序中的merge()函數,雖然方法不一樣,但是可惜的比較的次數還是沒有減少,仍然為1.5N次。在求解的過程中分別求出前後N/2個數的min和max,然後,取較小的min,較大的max即可。
這裡主要是提醒一下經常用的兩種思路:快排你的partion()和歸並裡的merge(),這兩個函數的解決問題的思路十分常用。通常在解決問題的時候,要想到他們,是一種解決的思路。
擴展問題
如果需要找出N個數中的第二大數,需要比較多少次呢?是否可以使用類似的分治思想來降低比較的次數呢?
思路一:
用兩個變量分別存最大值max1和次大值max2,遍歷數組:
初始化:max1=arr[0],max2=0;
先與max2比較,如果比max2大再和max1比較;
如果arr[i] >max1,則更新max=arr[i],max2=max1;
否則如果arr[i] > max2 && arr[i]< max1,則更新max2=arr[i];
否則,不進行更新操作。
這個方法最多的比較次數為2*N次,最大的值在最後面;最小N次第一個和第二個恰好就是最大和第二大的數。
思路二:快速選擇算法的思想。
先尋找出第k大的整數,然後再通過兩次遍歷前k大的數字找出第二大的數字,因為找出的前k個元素是不保證排序的。比較的次數為:找出前K個元素次時:最好k次,最壞N次。然後在前k個元素中找出第K個元素:比較的次數:k+k-1次。所以比較的次數為:最好3k-1次,最壞:N+2k-1次。