尋找陣列中的峰值(極大值)
技術標籤:資料結構和演算法
峰值元素是指其值大於左右相鄰值的元素。
給定一個輸入陣列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
}
}