[LeetCode解題攻略] 33. Search in Rotated Sorted Array

更新於 發佈於 閱讀時間約 7 分鐘

問題描述

給定一個按照升序排序的整數數組,但該數組可能在某個未知的軸點旋轉(例如,nums = [4,5,6,7,0,1,2])。請你在數組中搜索目標值 target,如果找到則返回其索引,否則返回 -1

限制條件

  • 時間複雜度應為 O(log n)。
  • 你可以假設數組中不存在重複元素。
  • 所有數值均在整數範圍內。

範例1:

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

範例2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

範例3:

Input: nums = [1], target = 0
Output: -1

解法一:改進的二分搜索

思路

由於數組經過旋轉,因此分為兩個有序區間。在進行二分搜索時,可以根據中點位置的數值和邊界條件來確定目標值所屬的區間,從而縮小搜索範圍。

步驟

  1. 初始化兩個指針 leftright,分別指向數組的起點和終點。
  2. 計算中點索引 mid = (left + right) // 2
  3. 如果中點值等於目標值,直接返回索引。
  4. 如果左半部分有序(即 nums[left] <= nums[mid]),判斷目標值是否落在此範圍:
    • 若是,將 right 移動到 mid - 1
    • 否則,將 left 移動到 mid + 1
  5. 如果右半部分有序,類似判斷目標值是否落在此範圍:
    • 若是,將 left 移動到 mid + 1
    • 否則,將 right 移動到 mid - 1
  6. 如果遍歷結束仍未找到目標值,返回 -1

程式碼

class Solution:
def search(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
# 判斷左半部分是否有序
if nums[left] <= nums[mid]:
if nums[left] <= target < nums[mid]:
right = mid - 1
else:
left = mid + 1
else: # 右半部分有序
if nums[mid] < target <= nums[right]:
left = mid + 1
else:
right = mid - 1
return -1

時間複雜度

  • 時間複雜度:O(log n),二分法的特性使得每次操作將搜索範圍縮小一半。
  • 空間複雜度:O(1),只使用常數額外空間。

解法二:遞歸二分搜索

思路

這是一個遞歸版本的二分搜索,邏輯與迭代法相同。根據旋轉後的特性,選擇遞歸左或右子區間。

程式碼

class Solution:
def search(self, nums: List[int], target: int) -> int:
def binary_search(left, right):
if left > right:
return -1
mid = (left + right) // 2
if nums[mid] == target:
return mid
if nums[left] <= nums[mid]: # 左半部分有序
if nums[left] <= target < nums[mid]:
return binary_search(left, mid - 1)
else:
return binary_search(mid + 1, right)
else: # 右半部分有序
if nums[mid] < target <= nums[right]:
return binary_search(mid + 1, right)
else:
return binary_search(left, mid - 1)

return binary_search(0, len(nums) - 1)

時間複雜度

  • 時間複雜度:O(log n),與迭代法相同。
  • 空間複雜度:O(log n),遞歸深度與二分次數相同。

解法三:線性搜索

思路

如果時間複雜度要求可以放寬,則可以通過遍歷數組進行查找。這是最簡單的方法,也是最花時間的方法。

程式碼

class Solution:
def search(self, nums: List[int], target: int) -> int:
for i in range(len(nums)):
if nums[i] == target:
return i
return -1

時間複雜度

  • 時間複雜度:O(n),最差情況需遍歷整個數組。
  • 空間複雜度:O(1)。

結論

  • 如果需要滿足 O(log n) 的時間複雜度,建議使用解法一(迭代法)或解法二(遞歸法)。
  • 若問題條件放寬,可使用解法三進行線性搜索。
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
給定一個只包含 '(' 和 ')' 的字串,找出其中包含的最長的有效括號子字串的長度。
實現一個函數來重新排列數字序列,使其成為下一個更大的排列。如果不存在更大的排列,則將其排列為最小的順序(即升序)。 這個排列必須是 "原地" 完成,也就是說,只能使用常數級額外空間。
給定一個字符串 s 和一個由多個單詞組成的列表 words,請找出所有能夠在字符串 s 中連續拼接所有單詞的子字符串的起始索引。
實作一個函數 divide(dividend, divisor),計算兩個整數 dividend 和 divisor 的商,並返回其結果。
實作一個函數 strStr(haystack, needle),用來找出字串 needle 在字串 haystack 中第一次出現的索引。如果 needle 不是 haystack 的一部分,則返回 -1。
給定一個整數數組 nums 和一個值 val,需要就地刪除數組中所有等於 val 的元素,並返回刪除後數組的新長度。 要求在 O(1) 額外空間內完成操作,並且元素的相對順序不需要保持一致。
給定一個只包含 '(' 和 ')' 的字串,找出其中包含的最長的有效括號子字串的長度。
實現一個函數來重新排列數字序列,使其成為下一個更大的排列。如果不存在更大的排列,則將其排列為最小的順序(即升序)。 這個排列必須是 "原地" 完成,也就是說,只能使用常數級額外空間。
給定一個字符串 s 和一個由多個單詞組成的列表 words,請找出所有能夠在字符串 s 中連續拼接所有單詞的子字符串的起始索引。
實作一個函數 divide(dividend, divisor),計算兩個整數 dividend 和 divisor 的商,並返回其結果。
實作一個函數 strStr(haystack, needle),用來找出字串 needle 在字串 haystack 中第一次出現的索引。如果 needle 不是 haystack 的一部分,則返回 -1。
給定一個整數數組 nums 和一個值 val,需要就地刪除數組中所有等於 val 的元素,並返回刪除後數組的新長度。 要求在 O(1) 額外空間內完成操作,並且元素的相對順序不需要保持一致。
你可能也想看
Google News 追蹤
提問的內容越是清晰,強者、聰明人越能在短時間內做判斷、給出精準的建議,他們會對你產生「好印象」,認定你是「積極」的人,有機會、好人脈會不自覺地想引薦給你
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
Thumbnail
魔鬼藏在二分搜尋裡!輸出值代表的意含、題意產生的邊界條件,寫完模板才是挑戰的開始 Orz
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們兩個字串。 第一個是指定順序的字串order。 第二個是輸入字串s。 要求我們依據order給定的順序,重新排列s。 如果出現order中沒有出現的字母,任意位置皆可。 合法答案可能不只一組,輸出其中一種即可。 題目的原文敘述 測試範例 Example
Thumbnail
題目敘述 題目會給定我們兩個整數陣列作為輸入nums1, nums2,要求我們找出兩個陣列的差異值。 找出在nums1但是不在nums2的元素,以陣列的形式放在answer[0]輸出。 找出在nums2但是不在nums1的元素,以陣列的形式放在answer[1]輸出。 題目的原文敘述
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,要求我們把裡面的0做元素交換,把0都搬到陣列的右邊。題目要求必須in-place在原本的陣列裡面做操作,不可以額外建立新的陣列。 題目的原文敘述 測試範例 Example 1: Input: nums = [0,1,0,3,12] Outpu
Thumbnail
題目敘述 題目給定我們一個輸入陣列nums 要求我們以正、負交叉排列的方式重組陣列,並且必須保持原本的相對順序。 並且以陣列的形式輸出返回答案。 例[5, 1, -2, -3] 重排後為 [5, -2, 1, -3] 題目的原文敘述 測試範例 Example 1: Input:
提問的內容越是清晰,強者、聰明人越能在短時間內做判斷、給出精準的建議,他們會對你產生「好印象」,認定你是「積極」的人,有機會、好人脈會不自覺地想引薦給你
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
Thumbnail
魔鬼藏在二分搜尋裡!輸出值代表的意含、題意產生的邊界條件,寫完模板才是挑戰的開始 Orz
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們兩個字串。 第一個是指定順序的字串order。 第二個是輸入字串s。 要求我們依據order給定的順序,重新排列s。 如果出現order中沒有出現的字母,任意位置皆可。 合法答案可能不只一組,輸出其中一種即可。 題目的原文敘述 測試範例 Example
Thumbnail
題目敘述 題目會給定我們兩個整數陣列作為輸入nums1, nums2,要求我們找出兩個陣列的差異值。 找出在nums1但是不在nums2的元素,以陣列的形式放在answer[0]輸出。 找出在nums2但是不在nums1的元素,以陣列的形式放在answer[1]輸出。 題目的原文敘述
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,要求我們把裡面的0做元素交換,把0都搬到陣列的右邊。題目要求必須in-place在原本的陣列裡面做操作,不可以額外建立新的陣列。 題目的原文敘述 測試範例 Example 1: Input: nums = [0,1,0,3,12] Outpu
Thumbnail
題目敘述 題目給定我們一個輸入陣列nums 要求我們以正、負交叉排列的方式重組陣列,並且必須保持原本的相對順序。 並且以陣列的形式輸出返回答案。 例[5, 1, -2, -3] 重排後為 [5, -2, 1, -3] 題目的原文敘述 測試範例 Example 1: Input: