162 尋找峰值(分析 遞迴二分查詢)

2021-10-11 12:04:00 字數 3244 閱讀 5806

1. 問題描述:

峰值元素是指其值大於左右相鄰值的元素。給定乙個輸入陣列 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素並返回其索引。陣列可能包含多個峰值,在這種情況下,返回任何乙個峰值所在位置即可。你可以假設 nums[-1] = nums[n] = -∞。

示例 1:

輸入: nums = [1,2,3,1]

輸出: 2

解釋: 3 是峰值元素,你的函式應該返回其索引 2。

示例 2:

輸入: nums = [1,2,1,3,5,6,4]

輸出: 1 或 5 

解釋: 你的函式可以返回索引 1,其峰值元素為 2;或者返回索引 5, 其峰值元素為 6。

說明:

你的解法應該是 o(logn)時間複雜度的。

2. 思路分析:

① 分析題目可以知道陣列中的元素分布主要存在以下三種情況:a:陣列元素都是公升序的,b:陣列元素都是降序的,c:陣列元素中有公升序與降序,下面是這三種情況對應的具體圖表:

當陣列中的元素都是公升序的時候那麼峰值元素為陣列中的最後乙個元素,當陣列元素為降序的時候那麼峰值元素為第乙個元素,當陣列元素有公升有降的時候那麼峰值元素在整個陣列區域性範圍中的位置,並且可以發現我們只需要判斷nums[i]是否大於nums[i + 1]即可找出陣列中的第乙個峰值元素,對於a情況在迴圈中會一直執行到陣列元素的末尾,可以發現都滿足nums[i] > nums[i + 1],所以我們最終迴圈執行完之後應該返回陣列的最後乙個元素的下標即可,對於b情況我們可以發現第乙個元素與第二個元素比較之後就滿足條件判斷所以返回0這個下標,對於c情況:如果有三個相鄰的元素a,b,c(b是峰值元素),首先判斷a > b是否成立,但是發現不成立,然後會判斷下乙個元素是否滿足b > c,發現滿足條件這個時候就返回元素b的下標,而b恰恰是峰值元素所以對於c情況只判斷nums[i] > nums[i + 1]也是適用的

② 除了①中的思路之外,力扣的題解中還提供了一種遞迴二分查詢的方法,感覺這種思路很巧妙(但是根據題目要求 o(logn)時間複雜度所以使用二分查詢也不難理解)之前的二分查詢陣列元素是有序的,而這裡因為陣列元素是無序的我們則需要根據題目的要求來更新二分查詢的範圍,我們可以根據中間位置的元素與其左邊或者是右邊的元素的大小關係來更新下一次二分查詢的範圍,當判斷中間位置的元素與其右邊元素的時候,也即nums[mid] < nums[mid + 1],如果滿足條件那麼更新左範圍,下一次二分查詢的範圍就是[mid + 1, r],因為峰值元素可能是存在右邊的,否則nums[mid] > nums[mid + 1],那麼峰值元素可能是存在左邊的,下一次二分查詢的範圍為[l, mid],我們可以在更新二分查詢範圍的時候使用遞迴的方法進行查詢(也可以迭代查詢)

③ 對於②中的方法我們可以判斷中間位置與左邊的元素或者是右邊的元素的大小元素,但是這兩者的中間值的計算是不一樣的,如果判斷nums[mid]與nums[mid + 1],那麼中間值mid = (l + r) // 2,如果判斷nums[mid]與nums[mid - 1]那麼中間值mid = (l + r + 1)// 2,其實我們可以舉出乙個具體的例子會更容易理解,因為在比較nums[mid]與nums[mid - 1]的時候如果mid = (l + r) // 2的話陣列會越界,而且有的時候可能會造成死迴圈,例如這個例子:[1, 2, 1, 3, 5, 6, 4]l = 5,r = 6在迴圈中範圍會一直保持在這裡所以導致了死迴圈,而且可以發現當l, r存在乙個為奇數的時候那麼加上1除以2之後會移動到下乙個位置,,所以當我們判斷nums[mid]與nums[mid - 1]的時候計算mid應該使用mid =(l + r + 1)// 2 

3. **如下:

分析:

from typing import list

class solution:

def findpeakelement(self, nums: list[int]) -> int:

for i in range(len(nums) - 1):

if nums[i] > nums[i + 1]: return i

return len(nums) - 1

遞迴二分查詢:

class solution:

def binarysearch(self, l: int, r: int, nums: list[int]):

if l == r: return l

mid = (l + r + 1) // 2

if nums[mid] > nums[mid - 1]:

return self.binarysearch(mid, r, nums)

return self.binarysearch(l, mid - 1, nums)

def findpeakelement(self, nums: list[int]) -> int:

return self.binarysearch(0, len(nums) - 1, nums)

from typing import list

class solution:

def binarysearch(self, l: int, r: int, nums: list[int]):

if l == r: return l

mid = (l + r) // 2

if nums[mid] < nums[mid + 1]:

return self.binarysearch(mid + 1, r, nums)

return self.binarysearch(l, mid, nums)

def findpeakelement(self, nums: list[int]) -> int:

# 下面是二分遞迴查詢

return self.binarysearch(0, len(nums) - 1, nums)

Leetcode 162 尋找峰值 二分)

如果沒有nums 1 nums n 這個條件,判斷極大值必須判斷nums i 1 nums i 1 但有了這個條件,以後,有些微妙。爬山演算法,設想從左邊向右出發,只要nums i nums i 1 即出現乙個下降的點,那麼這個點一定是極大值。時間複雜度是o n class solution ret...

Leetcode 162 尋找峰值(二分)

題目描述 峰值元素是指其值大於左右相鄰值的元素。給定乙個輸入陣列 nums,其中 nums i nums i 1 找到峰值元素並返回其索引。陣列可能包含多個峰值,在這種情況下,返回任何乙個峰值所在位置即可。你可以假設 nums 1 nums n 要求時間複雜度為log n 題解 log n 複雜度的...

leetcode 162 尋找峰值 二分法

峰值元素是指其值大於左右相鄰值的元素。給定乙個輸入陣列nums,其中nums i nums i 1 找到峰值元素並返回其索引。陣列可能包含多個峰值,在這種情況下,返回任何乙個峰值所在位置即可。你可以假設nums 1 nums n 示例 1 輸入 nums 1,2,3,1 輸出 2解釋 3 是峰值元素...