二分查找類算法題

 

 

 

二分查找基本模版:


def two_find(nums, target ,l ,r):
    if l>r: return False
    m = (l+r)//2
    if nums[m]==target:
        return True
    elif nums[m] < target:
        return two_find(nums, target, m+1, r)
    elif nums[m] > target:
        return two_find(nums, target, l, m-1)

def two_find2(nums,target):
    l,r = 0, len(nums)-1
    while l<=r:
        m = (l+r)//2
        if nums[m]==target: return True
        elif nums[m]<target:    l = m+1
        else : r = m-1
    return False

if __name__ == '__main__':
    nums = [1,5,7,8,9,12,16,19,23]
    target = 4
    target = 23
    r = two_find(nums, target, 0, len(nums)-1)
    # r = two_find2(nums, target)
    print(r)

33. 在旋轉數組中查找元素

假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,1,2,4,5,6,7] 可能變爲 [4,5,6,7,0,1,2] )。
搜索一個給定的目標值,如果數組中存在這個目標值,則返回它的索引,否則返回 -1 。
你可以假設數組中不存在重複的元素。
你的算法時間複雜度必須是 O(log n) 級別。
輸入: nums = [4,5,6,7,0,1,2], target = 0
輸出: 4
輸入: nums = [4,5,6,7,0,1,2], target = 3
輸出: -1
方法思路:
1.根據 首尾判斷是否旋轉
2.若未旋轉,直接二分查找(注意:可以直接判斷target是否在首尾之內,否則直接返回-1)
3.若旋轉, 先找旋轉點(以找到最大值爲例)
(1)情況一:target在[0,index_max]之內:此範圍二分查找
(2)情況二:target在[index_max+1,len(nums)-1]之內:此範圍二分查找
(3)情況三:若不在以上兩種情況則直接返回-1

class Solution:
    def search(self, nums, target):
        if len(nums)<1: return -1
        # 二分查找
        def two_find(l,r):
            if l>r: return -1
            m = (l+r)//2
            if nums[m]==target: return m
            elif nums[m]>target: return two_find(l,m-1)
            else: return two_find(m+1,r)

        # 尋找最大的 max_index 值
        def find_max(l,r):
            m = (l+r)//2
            if nums[m]>nums[m+1]: return m
            elif nums[m]>nums[0]: return find_max(m+1,r)
            else : return find_max(l,m-1)

        # 正常的升序數組
        if nums[len(nums)-1]>nums[0]:
            return two_find(0,len(nums)-1)
        else:
            max_index = find_max(0,len(nums)-1)
            if nums[max_index]>=target and target>=nums[0]: return two_find(0,max_index)
            elif target>=nums[max_index+1] and target<nums[-1]:return two_find(max_index+1,len(nums)-1)
            else: return -1


    from typing import List
    def search2(self, nums: List[int], target: int) -> int:
        if len(nums) < 1: return -1
        if len(nums) == 1:
            return 0 if nums[0] == target else -1

        # 二分查找
        def two_find(l, r):
            while l <= r:
                m = (l + r) // 2
                if nums[m] == target:
                    return m
                elif nums[m] < target:
                    l = m + 1
                else:
                    r = m - 1
            return -1

        def find_max(nums):
            l, r = 0, len(nums) - 1
            while l <= r:
                m = (l + r) // 2
                if m != len(nums) - 1 and nums[m] > nums[m + 1]:
                    return m
                elif nums[0] <= nums[m]:
                    l = m + 1
                else:
                    r = m - 1
            return len(nums) - 1

        max_id = find_max(nums)
        # print(max_id)
        if target <= nums[max_id] and target >= nums[0]:
            res = two_find(0, max_id)
        else:
            res = two_find(max_id + 1, len(nums) - 1)
        return res

 

34.在排序數組中查找元素的 第一個和最後一個位置

給定一個按照升序排列的整數數組 nums,和一個目標值 target。
找出給定目標值在數組中的開始位置和結束位置。
你的算法時間複雜度必須是 O(log n) 級別。
如果數組中不存在目標值,返回 [-1, -1]。
--------------------------------------------------------------------------------
輸入: nums = [5,7,7,8,8,10], target = 8
輸出: [3,4]
輸入: nums = [5,7,7,8,8,10], target = 6
輸出: [-1,-1]
class Solution:
    def searchRange(self, nums, target):
        # 二分查找--左邊界
        def find_left(l ,r):
            if l> r: return -1
            m = (l + r) // 2
            if (target == nums[m] and m == 0) or (target == nums[m] and target != nums[m - 1]):
                return m
            elif target < nums[m] or (target == nums[m] and target == nums[m - 1]):
                return find_left(l, m - 1)
            else:
                return find_left(m + 1, r)

        # 查找最右邊界 index
        def find_right(l, r):
            if l > r: return -1
            m = (l + r) // 2
            if (target == nums[m] and m == len(nums) - 1) or (target == nums[m] and target != nums[m + 1]):
                return m
            elif target > nums[m] or (target == nums[m] and target == nums[m + 1]):
                return find_right(m + 1, r)
            else:
                return find_right(l, m - 1)

        if len(nums) == 0: return [-1, -1]
        if target >= nums[0] and target <= nums[-1]:
            left = find_left(0, len(nums) - 1)
            if left == -1: return [-1, -1]
            if left == len(nums) - 1 or nums[left + 1] != target:
                return [left, left]
            else:
                right = find_right(left + 1, len(nums) - 1)
                return [left, right]
        else:
            return [-1, -1]


if __name__=="__main__":
    s=Solution()
    nums=[1]
    target=1
    r = s.searchRange(nums,target)
    print(r)

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章