1. 程式人生 > 其它 >尋找陣列中的峰值(極大值)

尋找陣列中的峰值(極大值)

技術標籤:資料結構和演算法

峰值元素是指其值大於左右相鄰值的元素。

給定一個輸入陣列nums,其中 nums[i] ≠ nums[i+1],找到峰值元素並返回其索引。

陣列可能包含多個峰值,在這種情況下,返回任何一個峰值所在位置即可。

你可以假設nums[-1] = nums[n] = -∞。

輸入: nums = [1,2,3,1]
輸出: 2
解釋: 3 是峰值元素,你的函式應該返回其索引 2。

輸入: nums = [1,2,1,3,5,6,4]
輸出: 1 或 5
解釋: 你的函式可以返回索引 1,其峰值元素為 2;
或者返回索引 5, 其峰值元素為 6。


首先還是常規思路, 遍歷一遍找出滿足條件的值即可, 需要特殊處理下頭部和尾部, 如果頭部尾部已經滿足條件了, 就不需要再遍歷了, 直接返回即可.

class Solution {

    func findPeakElement(_ nums: [Int]) -> Int {

        // 陣列元素只有1個
        if nums.count == 1 {
            return 0
        }
        // 陣列元素超過2個, 檢視頭部和尾部是否滿足條件,如果滿足可直接返回
        // 檢視頭部是否滿足條件
        if nums[0]>nums[1] {
            return 0
        }
        // 檢查尾部是否滿足條件
        if nums.last! > nums[nums.count-2] {
            return nums.count-1
        }
        // 從中間開始遍歷查詢
        for i in 1..<nums.count-1  {
            if nums[i]>nums[i-1] && nums[i]>nums[i+1] {
                return i
            }
        }

        return -1
    }

}

題目上有提示說可以做到O(logN)的時間複雜度, logN的時間複雜度自然就想到了2分查詢.我們可以將 nums 陣列中的任何給定序列視為交替的升序和降序序列。通過利用這一點,以及“可以返回任何一個峰作為結果”的要求,我們可以利用二分查詢來找到所需的峰值元素。

在簡單的二分查詢中,我們處理的是一個有序數列,並通過在每一步減少搜尋空間來找到所需要的數字。在本題中,我們需要對二分查詢進行一點修改。首先從陣列 nums中找到中間的元素 mid。若該元素恰好位於降序序列或者一個區域性下降坡度中(當nums[mid] > 右側num[mid+1]時),則說明峰值是自己或者在本元素的左邊。於是,我們將搜尋空間縮小為 [left , mid] (包括mid本身)。

若該元素恰好位於升序序列或者一個區域性上升坡度中(當nums[mid] < num[mid+1]時),則說明峰值會在本元素的右邊(mid肯定不會是峰值了,因為nums[mid] < num[mid+1] )。於是,我們將搜尋空間縮小為 [mid+1, right]的右邊。

就這樣迴圈下去,我們不斷地縮小搜尋空間,直到搜尋空間中只有一個元素,該元素即為峰值元素。

class Solution {

    func findPeakElement(_ nums: [Int]) -> Int {
        var left = 0
        var right = nums.count-1
        while left < right {
            let mid = Int((left + right)/2)
            if nums[mid]>nums[mid+1] {
                right = mid
            }  else {
                left = mid+1
            }

        }
        return left

    }

}