Photo by Daniel Chen on Unsplash

LEETCODE 解題紀錄 #4

33. Search in Rotated Sorted Array

└─解題難度:MEDIUM

Kevin Cheng
Cow Say
Published in
Aug 30, 2021

--

獻給所有對 Binary Search 感到苦手的人。

如果你有以下症狀,諸如渾渾噩噩算不清邊界、要等號還是不要等號、選左還選右等等困擾,請盡速前往 LeetCode 教學 Binary Search 篇對症下藥及時根治🚑

題目說明

給定一個整數陣列,要找出目標數字出現在陣列中的索引值,若不存在於陣列中則返回 -1。

與典型的 Binary Search 不同的是,該陣列在輸入前會經過一次程度不一的旋轉。

以 [1,2,3,4,5] 為例,若向右旋轉 1 個位置,則會得到 [5,1,2,3,4],其中原先最右邊的 5 穿過了邊界來到了新位置 (即最左邊)。

解題分析

由於題目要求時間複雜度須為 O(log N) 以下,因此勢必要使用 Binary Search,在每一輪搜尋時將搜索空間 (Search space) 一次縮小一半。

典型的 Binary Search 題目都是從有序的陣列中進行搜尋,因為在有序的情況下,我們可以透過 left, middle, right 三個點去判斷搜尋的目標在哪一塊子搜索空間內,並排除其他搜索空間。

本題的整數陣列經過旋轉後的數值大小關係可以下圖為例。

left, right, mid1 和 mid2 的間距並未按照比例去繪圖,主要用來示意其在 y 軸上 (nums[i]) 的大小關係。

假設對兩點 left, right 取中點得到 mid1,我們可以從圖中看出,mid1 的左半部可保證為有序排列,右半部則包含了旋轉造成的切面 (圖中深色虛線)。

透過圖中我們可以歸納出 mid1 的特徵包含了 nums[mid1] ≥ nums[left] 這個條件。

在 mid1 的情況下,我們可以判斷 target 是否存在於 nums[left] 和 nums[mid1] 之間,去決定要保留哪一塊搜索空間 ([left, mid1] 或是 [mid1, right])。

在另一個情況中,若對 left, right 取中點得到 mid2,我們可發現 nums[right] ≥ nums[mid2],並且可透過判斷 target 是否存在於 nums[mid2] 和 nums[right] 之間去決定要保留的搜索空間。

在這個演算法中,我們只依賴其中一半的子搜索空間去判斷要保留哪一邊,並且被依賴的那半個搜索空間是符合有序條件的那一半。

照這樣看來,一個未經旋轉的有序陣列也適用於這個演算法,因為這個有序陣列的兩個子搜索空間都是有序的,我們只要任選其中一半進行上述之判斷即可知道要保留哪一半。

解決方案

每次對 left, right 取中點 mid 之後,先判斷是 [left, mid] 這個空間有序 (mid1 情況) 還是 [mid, right] 是有序的 (mid2 情況)。

接著按照有序的那半個搜索空間,我們就可以判斷出要如何修改 left 或 right 縮小搜索空間。

--

--

Kevin Cheng
Cow Say
Editor for

貓奴 / 後端工程師 / 人生最重要的四件事:溫柔、勇敢、自由、浪漫