算法:二分搜索相关-python

二分搜索

首先掌握一个套路

  • 长度为0的情况
  • while循环,双指针
  • 写判断条件
  • 兜底情况

其次,面试时的三问:

  • 数组有无重复元素
  • 是否有序
  • 是否有负值

相关题目

  • 旋转有序数组的搜索:记住无论怎么旋,有一部分会是有序的

153. 寻找旋转排序数组中的最小值

【无重复元素】

    def findMin(self, nums: List[int]) -> int:
        if len(nums) == 0:
            return -1
        n =len(nums)
        l,r = 0 ,n-1
        while l +1 < r:
            if nums[r] > nums[l]:
                return nums[l]
            mid = l + (r - l) // 2
            if nums[mid] >= nums[l]:
                l = mid + 1 
            else:
                r = mid
            
        return nums[l] if nums[l] < nums[r] else nums[r]

154. 寻找旋转排序数组中的最小值 II

【有重复元素】

    def findMin(self, nums: List[int]) -> int:
        if len(nums) == 0:
            return -1
        n =len(nums)
        l,r = 0 ,n-1
        while l +1 < r:

            if nums[r] > nums[l]:
                return nums[l]
            mid = l + (r - l) // 2
            if nums[mid] > nums[l]:
                l = mid + 1
            elif nums[mid] == nums[l]:
                while l < mid and nums[l] == nums[mid]:
                    l += 1
            else:
                r = mid            
        return nums[l] if nums[l] < nums[r] else nums[r]

旋转数组有无重复元素是很常见的问题,有重复元素通常会体现在端端相等,就需要多个判断并处理

面试题 10.03. 搜索旋转数组

搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。

先来看个错误的做法:

    def search(self, nums: List[int], target: int) -> int:
        if len(nums) == 0:
            return -1
        n =len(nums)
        l,r = 0 ,n-1
        while l +1 < r:
            mid = l + (r-l) // 2
            if nums[l] < nums[mid]:
                if nums[l] <= target and target <= nums[mid]:
                    r = mid
                else:
                    l = mid
            elif nums[l] > nums[mid]:
                if nums[mid] <= target and target <= nums[r]:
                #if nums[l] <= target or target <= nums[mid]:
                    l = mid
                else :
                    r = mid
            else :
                if nums[l] != target:
                    l += 1
                else:
                    r = mid
        if nums[l] == target:
            return l
        if nums[r] == target:
            return r
        return -1

错在哪?[5,5,5,1,2,3,4,5] 5,对于这种类型的例子会错误。

原因在于 nums[l] > nums[mid]时,右部分是有序的,我想看target是否在右边。对于上述例子,5在右边确实有,但因为有重复元素,左部分同样有。要返回最小索引,就必须全部在左部分判断。

改成注释的部分,即可。或者加上一个判断语句,如果是第一个元素就是target,返回。

9.供暖器

对于每个房子,找到离它最近的供暖器,记录下距离。找出所有距离的最大值即可。

74.搜索二维矩阵

记住有序的二维矩阵,看左对角,上方小于右边大于。

面试题03. 数组中重复的数字

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

  • 解法一:排序后找, O ( n l o g n ) O(nlogn) O(nlogn)
  • 解法二:哈希表。用一个字典记录。空间换时间,遍历一遍即可。
  • 解法三:用数组的性质,nums[i] = i,继续;nums[i] != i时,比较 nums[i] 与 nums[nums[i]],如果相等,说明这个元素是重复的。如果不等,交换位置,把nums[i]放到其有序的位置上,这样就可以找到重复的。

287. 寻找重复数

给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。

    def findDuplicate(self, nums: List[int]) -> int:
        l = 1
        r = len(nums) - 1
        while l < r: 
            count = 0
            mid = l + ( r - l ) // 2
            for i in nums :
                if i <= mid:
                    count += 1

            if count <= mid:
                 l = mid + 1
            else :
                r = mid 
        return l  

要注意与上一题的不同,这边是1到n。,具体差别在哪里还需要思考(坑)

另一种解法,还没领悟。

def findDuplicate(nums):
    # The "tortoise and hare" step.  We start at the end of the array and try
    # to find an intersection point in the cycle.
    slow = 0
    fast = 0
    while True:
        slow = nums[slow]
        fast = nums[nums[fast]]

        if slow == fast:
            break
    finder = 0
    while True:
        slow   = nums[slow]
        finder = nums[finder]
        if slow == finder:
            return slow

可以确认,如果是0-n-1同样不行。因为nums[0] = 0时,永远在原地踏步。

(未做)4. 寻找两个正序数组的中位数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值