二分法查找_34;35;69;367;704

二分法

1、数组为有序数组

2、区间优先选择左闭右闭的区间,0---len(nums)-1

3、每个middle做对比的情况下都要进行边界条件更新,除非直接满足条件return。middle大:更新right = middle - 1,middle小:更新left = middle + 1

4、多考虑边界条件,高含金量:搜索左边界,搜索右边界
# 704.二分查找.py
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1

        while left <= right:
            middle = (left + right) // 2
            if nums[middle] < target:
                left = middle + 1
            elif nums[middle] > target:
                right = middle - 1
            else:
                return middle
        return -1
# 35.搜索插入位置.py
# 最终版
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums) -1
        while left <= right: # 为什么是必须考虑等于的情况?因为这是一个左右都闭合的空间。在查找时即使左右已经相等,也需要进行加减1,变成left比right大的情况
            middle = (left + right) //2
            if nums[middle] == target:
                return middle
            elif nums[middle] > target:
                right = middle - 1
            elif nums[middle] < target:
                left = middle + 1
        return right + 1 # 为什么不是left-1?因为此时left已经比right大了,right在左边,当然是左+1
# 34.在排序数组中查找元素的第一个和最后一个位置.py
class Solution:
    def searchRange(self, nums: list[int], target: int) -> list[int]:

        def searchLeft(nums:list[int], target:int) -> int: # 寻找左边界
            leftBorder = -10
            left, right = 0, len(nums) - 1
            if len(nums) == 0:
                return [-1, -1]
            else:
                while left <= right:
                    middle = (left + right) // 2
                    if nums[middle] < target:
                        left = middle +1
                    elif nums[middle] == target:
                        right = middle - 1
                        leftBorder = right  # 为什么不是middle?因为计算出来的左边界是不包含target的右边界
                    elif nums[middle] > target:
                        right = middle - 1  # 重建左边界不断逼近实际左边界
                        leftBorder = right  # 如果target在nums的左边,middle永远大于target,leftBorder变为-1

                return leftBorder


        def searchRight(nums:list[int], target:int) -> int:
            rightBorder = -10
            left, right = 0, len(nums) - 1
            while left <= right:
                middle = (left + right) // 2
                if nums[middle] > target:  # 如果target在nums的左边,middle永远大于target,此时leftBorder为-1,rightBorder的更新条件不会被触发,所以最后的rightBorder为初始值-10
                    right = middle - 1
                elif nums[middle] < target:
                    left = middle + 1
                    rightBorder = left  # 为什么不是middle?
                elif nums[middle] == target:
                    left = middle +1
                    rightBorder = left
            return rightBorder

        leftBoder = searchLeft([1,2,2,2,2,3,4,5,6], 2)
        print(leftBoder)
        rightBoder = searchRight([1,2,2,2,2,3,4,5,6], 2)
        print(rightBoder)
        if leftBoder == -10 or rightBoder == -10:  # 但凡有一个初始值没被改变的,就返回[-1, -1]
            return [-1, -1]
        if rightBoder - leftBoder > 1:  # 为什么没有等于? 如果target卡在中间而且没有相同的值的时候,rightBoder - leftBoder应该等于1,应该返回[-1, -1]*****大于1说明存在有意义的左右边界值
            return [leftBoder + 1, rightBoder - 1]  # 因为计算出来的右边界是不包含target的右边界
        return [-1, -1]
# 69.x的平方根.py
# # 参考
# class Solution:
#     def mySqrt(self, x: int) -> int:
#         l, r, ans = 0, x, -1
#         while l <= r:
#             mid = (l + r) // 2
#             if mid * mid <= x:
#                 ans = mid
#                 l = mid + 1
#             else:
#                 r = mid - 1
#         return ans





# # 提交版
# class Solution:
#     def mySqrt(self, x: int) -> int:
#         left, right, ans = 0, x, -1
#         while left <= right:
#             middle = (left + right) // 2
#             if middle * middle == x:
#                 ans = middle
#                 # 为什么等于的时候还要更新左边界?即使等于x了,也要继续进行循环,要是不更新left的值那就永远都循环下去了,所以不管什么情况都要更新边界条件
#                 left = middle + 1  # 如果不想更新了,也可以直接return ans,没问题
#             elif middle * middle < x:
#                 ans = middle
#                 left = middle + 1
#             elif middle * middle > x:
#                 # ans = middle # 当尝试的middle平方大于x时,并不需要储存ans,首先是因为这个middle绝对不可能是解,其次假如最后一次尝试是这个情况的话,会更新成错误的ans
#                 right = middle -1
#         return ans




# # 调试
# def mySqrt(x: int) -> int:
#         left, right, ans = 0, x, -1
#         while left <= right:
#             middle = (left + right) // 2
#             if middle * middle == x:
#                 ans = middle
#                 # left = middle + 1
#             elif middle * middle < x:
#                 ans = middle
#                 left = middle + 1
#             elif middle * middle > x:
#                 # ans = middle
#                 right = middle -1
#         return ans
# print(mySqrt(4))

# 二刷:问题出在了left = middle + 1,写成减号了,另外ans = middle;return ans不能写成return ans == middle,进一步探索
class Solution:
    def mySqrt(self, x: int) -> int:
        left, right, ans = 0, x, -1
        while left <= right:
            middle = (left + right) // 2
            if middle * middle == x:
                ans = middle
                return ans
            elif middle * middle > x:
                right = middle - 1
            elif middle * middle < x:
                ans = middle
                left = middle + 1
        return ans
# 367.有效的完全平方数.py
# 参考
class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        left, right = 0, num
        while left <= right:
            mid = (left + right) // 2
            square = mid * mid
            if square < num:
                left = mid + 1
            elif square > num:
                right = mid - 1
            else:
                return True
        return False

# 1.0 一遍通过
class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        left, right = 0, num
        while left <= right:
            middle = (left + right) // 2
            if middle * middle == num:
                return True
            elif middle * middle > num:
                right = middle - 1
            elif middle * middle < num:
                left = middle + 1
        return False

上一篇:2.11 Go音乐播放器


下一篇:springboot-yaml配置注入