算法題--在旋轉(zhuǎn)過的有序數(shù)組中尋找指定值所處位置

image.png

0. 鏈接

1. 需求

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

Your algorithm's runtime complexity must be in the order of O(log n).

Example 1:

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

Example 2:

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

2. 思路1: 先用二分法找到數(shù)組旋轉(zhuǎn)點, 再從兩部分數(shù)組中分別用二分法尋找

2.1 算法步驟

例如從nums=[4, 5, 6, 7, 0, 1, 2]中查找target=0
過程如下:

1) 先用二分法尋找到旋轉(zhuǎn)點7對應下標split_index=3
2) 如果target < nums[0]
        則從nums[0: split_index + 1]中二分查找target所處下標
   否則
        則從nums[split_index + 1:-1]中二分查找target所處下標result_index
        如果結(jié)果不為-1,則返回split_index + 1 + result_index

2.2 代碼

# coding:utf8


class Solution:
    def binary_search(self, nums, target):
        left = 0
        right = len(nums) - 1

        while left <= right:
            mid = (left + right) // 2
            if nums[mid] == target:
                return mid
            elif target > nums[mid]:
                left = mid + 1
            elif target < nums[mid]:
                right = mid - 1

        return -1

    def search_pivot(self, nums):
        left = 0
        right = len(nums) - 1

        while left < right:
            mid = (left + right) // 2
            if nums[mid] > nums[left] and nums[mid] > nums[right]:
                left = mid
            elif nums[mid] < nums[left] and nums[mid] < nums[right]:
                right = mid
            else:
                break

        return left

    def search(self, nums, target: int) -> int:
        if len(nums) == 0:
            return -1

        if nums[0] < nums[-1]:
            return self.binary_search(nums, target)

        pivot_index_left = self.search_pivot(nums)
        if pivot_index_left == -1:
            return -1

        if target < nums[0]:
            target_idx = self.binary_search(nums[pivot_index_left + 1:], target)
            return pivot_index_left + 1 + target_idx if target_idx != -1 else -1
        else:
            return self.binary_search(nums[:pivot_index_left + 1], target)


solution = Solution()
print(solution.search([4, 5, 6, 7, 0, 1, 2], 0))  # 4
print(solution.search([], 1)) # -1
print(solution.search([1], 1)) # 0
print(solution.search([1, 3], 1)) # 0
print(solution.search([1, 3, 0], 0)) # 2

2.3 結(jié)果

image.png

3. 思路2: 只用一次二分查找解決問題

3.1 算法步驟

1. 已知數(shù)組含有兩個分別有序的子數(shù)組, 
2. 定義left=0, right=len(array) - 1,
 while left <= right do
    計算mid = (left + right) // 2,
     如果 nums[mid] == target 則
        返回mid
     否則
        判斷mid處元素和target是否處于同一個子數(shù)組
            1) 如果array[mid] >= nums[0] > target, 即mid處于左子數(shù)組, 而target處于右子數(shù)組, 此時需要
                left = mid + 1, 試圖接近target所處的位置
            2) 如果array[mid] < nums[0] <= target, 即mid處于右子數(shù)組, 而target處于左子數(shù)組, 此時需要
                right = mid - 1, 試圖接近target所處的位置
            3) 1和2都不滿足, 則說明mid和target處于同一個子數(shù)組,此時可以走正常二分查找的步驟, 即:
                if target < nums[mid]:
                    right = mid - 1
                else:
                    left = mid + 1
        
 return -1

3.2 代碼

class SolutionSimple:
    def search(self, nums, target):
        if len(nums) == 0:
            return -1

        left = 0
        right = len(nums) - 1

        while left <= right:
            mid = (left + right) // 2
            if nums[mid] == target:
                return mid

            if nums[mid] >= nums[0] > target:
                left = mid + 1
            elif nums[mid] < nums[0] <= target:
                right = mid - 1
            else:
                if target > nums[mid]:
                    left = mid + 1
                else:
                    right = mid - 1

        return -1


solution = SolutionSimple()
print(solution.search([4, 5, 6, 7, 0, 1, 2], 0))    # 4
print(solution.search([], 1))         # -1
print(solution.search([1], 1))        # 0
print(solution.search([1, 3], 1))     # 0 
print(solution.search([1, 3, 0], 0))  # 2
print(solution.search([4, 5, 6, 7, 0, 1, 2], 3))    # -1

3.3 結(jié)果

image.png
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 3,191評論 0 3
  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,914評論 0 13
  • NAME dnsmasq - A lightweight DHCP and caching DNS server....
    ximitc閱讀 2,992評論 0 0
  • 夜夜生哥閱讀 644評論 0 0
  • 從零學Laravel目錄列表 上一節(jié)課我們學習了從數(shù)據(jù)庫拿數(shù)據(jù),下面我們來學習下通過創(chuàng)建一條記錄到數(shù)據(jù)庫,常用的操...
    ZhouJiping閱讀 458評論 0 1

友情鏈接更多精彩內(nèi)容