2024.3.(24,25号)力扣刷题记录-二分查找学习记录2

一、学习视频

【搜索旋转排序数组【基础算法精讲 05】】 https://www.bilibili.com/video/BV1QK411d76w/?share_source=copy_web&vd_source=dc0e55cfae3b304619670a78444fd795

二、跟练代码记录

1.162. 寻找峰值

(1)排序,时复O(nlogn)(函数)或O(n)(遍历寻找)

class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        # 排序 时复O(nlogn) 或 O(n)
        # 最大值肯定是峰值
        idx = list(range(len(nums)))
        idx.sort(key = lambda x : nums[x],reverse = True)
        return idx[0]

(2)二分查找,参考学习视频。

class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        # 二分查找
        # 爬坡
        left, right = 0,len(nums) - 2
        #nums[-1] = nums[n] = -∞,任何情况最后一个都不为峰顶
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] < nums[mid + 1]:
                #nums[i] != nums[i + 1]
                left = mid + 1
            else:
                right = mid - 1
        return left

2024.3.25续:

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

二分,参考视频。视频将两种情况都包含了。

class Solution:
    def findMin(self, nums: List[int]) -> int:
        # 二分查找
        # # 原序列
        # if nums[0] <= nums[-1]:
        #     return nums[0]
        l,r = 0,len(nums)-2     #闭区间
        # 两段递增序列
        while l <= r:
            mid = (l + r) // 2
            # if nums[l] >= nums[mid]:  #有错
            if nums[-1] > nums[mid]:
                r = mid - 1
            else:
                l = mid + 1
                # 如果-1位为最小值,则最后l会指向-1
        return nums[l]

3.33. 搜索旋转排序数组

二分,参考视频。

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        # 二分
        def is_blue(i:int) -> bool:
            end = nums[-1]
            if nums[i] > end:
                return target > end and nums[i] >= target
            else:
                return target > end or nums[i] >= target
        # 闭区间
        l,r = 0, len(nums)-1
        while l <= r:
            mid = (l + r) // 2
            if is_blue(mid):
                r = mid - 1
            else:
                l = mid + 1
        if l == len(nums) or nums[l] != target:
            return -1
        return l

 注意:寻找target的题需要验证target是否被找到。

 三、课后作业

1.1901. 寻找峰值 II

来自灵神题解(. - 力扣(LeetCode))。太牛了!!!我还能说什么!!

class Solution:
    def findPeakGrid(self, mat: List[List[int]]) -> List[int]:
        # 二分,对行二分
        left, right = 0, len(mat) - 2
        while left <= right:
            i = (left + right) // 2     #即mid
            mx = max(mat[i])
            if mx > mat[i + 1][mat[i].index(mx)]:
                right = i - 1    #始终记住是未确认值的闭区间
            else:
                left = i + 1
        return [left,mat[left].index(max(mat[left]))]

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

二分,参考灵神题解(. - 力扣(LeetCode))。想到了与区间右端点进行比较,但是没有想到与区间右端点加一进行比较(与前面区间【0,n-2】数据与n-1位进行比较相同)。与区间内端点进行比较容易漏解。

class Solution:
    def findMin(self, nums: List[int]) -> int:
        # # 求最小值
        # return min(nums)
        # 二分
        l,r = 0,len(nums)-2
        while l <= r:
            mid = (l+r) // 2
            if nums[mid] == nums[r+1]:
                # 去掉右侧重复元素
                r -= 1
            elif nums[mid] < nums[r+1]:
                r = mid - 1
            else:
                l = mid + 1
        return nums[l]

在评论也看到另一种写法(. - 力扣(LeetCode)),将左端重复数去除即可。其实道理都差不多,就是将重复数去除即可(保证能够对最小值存在区间进行判断)。一个是在比较时去除(灵神);一个是在比较前就去除(评论),变为常规题型。

对左边数进行去除。来自评论解法(链接如上)。

class Solution:
    def findMin(self, nums: List[int]) -> int:
        # 二分2
        # 对左边数进行去除
        l,r = 0,len(nums)-2
        while l <= r and nums[l] == nums[-1]:
            # 跟参照物进行比较
            l += 1
        while l <= r:
            mid = (l+r) // 2
            if nums[mid] <= nums[-1]:
                r = mid - 1
            else:
                l = mid + 1
        return nums[l]

对右边数进行去除。根据同样的道理我写出了对右边数进行去除的代码:

class Solution:
    def findMin(self, nums: List[int]) -> int:
        # 二分3
        # 对右边数进行去除
        l,r = 0,len(nums)-2
        while l <= r and nums[l] == nums[r+1]:
            # 跟参照物进行比较
            r -= 1
        while l <= r:
            mid = (l+r) // 2
            if nums[mid] <= nums[r+1]:    #注意等号
                r = mid - 1
            else:
                l = mid + 1
        return nums[l]

总结:二分好难,还需要多练练。

感谢你看到这里!一起加油吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值