LeetCode-33. Search in Rotated Sorted Array

前言

这个点写博客,真的是有点被逼无奈呀,室友每天晚上都睡得很晚(不是打游戏,是在学习),我是基本全黑的情况下还要酝酿很久才能睡着的人,所以更别提有光和有鼠标键盘声的环境下了,既然睡不着就起来刷题写博客吧,总比在床上玩手机来的好!所以这应该算是我的第一篇深夜博客吧,以后估计还会有更多吧。。。

问题描述

在这里插入图片描述

解法一

看到这个问题第一个想法肯定就是二分法呀,又要求了时间复杂度在log(n),所以二分法没跑了。但是这个二分法写起来却有点麻烦,因为边界条件可能不是那么好写。下面的代码就是我的垃圾解法,虽然很垃圾,但还算逻辑清晰。下面简单介绍一下思路:
首先先二分法取一个点current,然后和target比较,如果比目标值大,则说明应该向递减的方向上移动,反之则向递增的方向上移动。如果是完全排好序的列表,那就很好解决啦,直接左右移动即可,但是现在因为出现了旋转,所以就得判断此时递增的方向在哪,递减的方向在哪了。
判断的大致逻辑是这样的:
首先先将位于列表左边的递增序列称为左上升区,右边的递增序列称为右上升区,同时可以发现,左上升区的所有值都大于右上升区的值。
当我们已经知道了current和target的大小后,如果需要找到更大的值,先判断current是在左上升区还是在右上升区,判断的方法就是用current和list中的最后一个值(也就是右上升区的最大值进行比较),如果current比其大,则说明current肯定在左上升区,那么此时比current大的值肯定在current的右边,所以begin=current,end不变,下一个区间就向右方移动。而如果current在右上升区,那么此时比current大的值既可能在current的右边,也可能在current的左边,因此这个时候还得判断,target是位于左区还是右区,判断方法同样是和list的最后一个元素比较,如果大则说明target位于左上升区,则向current的左边搜索,反之向右边搜索。这样算是讨论好了一种情况,同样地,对于current在右上升区的情况做类似的讨论。
估计你看到这块就已经很迷糊了,说实话,我也迷了,唉,看来表述能力还有待提高呀,也可能是深夜发贴的原因吧。。。有啥不明白的直接评论即可!

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n = len(nums)
        if n==0:
            return -1
        begin = 0
        end = n-1
        current = (int)((begin+end)/2)
        while end >= begin:
            print(current)
            if nums[current] == target:
                return current
            elif nums[current]>target:#往小的方向变
                if nums[current] > nums[end]:#当前位置在左边上升区
                    if target >nums[end]:#目标位于左边
                        end = current-1
                    else:#目标位于右边
                        begin = current+1
                else:#当前位置在右边上升区 目标只能位于左边
                    end = current-1 
            else:#往大的方向变
                if nums[current] > nums[end]:#当前位置在左边上升区
                    begin = current+1#目标位置只能位于当前位置右边
                else:#当前位置在右边上升区
                    if target >nums[end]:#目标位于左边
                        end = current-1
                    else:#目标位于右边
                        begin = current+1
            current = (int)((begin+end)/2)
        return -1

解法二

其实上面的解法虽然也是log(n)的复杂度,但是分析起来很麻烦,逻辑错一点就会有问题,其实有一种更好的方法(看了第一名的代码后才想到的),就是先确定list旋转点的位置,然后再确定target是落在左上升区还是右上升区,如果旋转点位置已知,target位于的分区也已知,那么就可以只在这个分区内找target就行啦,而这个分区是排好序的,最适合二分查找。然后就搞定了,逻辑清晰,步骤明确,我怎么就想不到呢?果然,人和人之间的差距还是蛮大的。。。。
由于这个想法刚看到,还没时间来的及实现,现在也凌晨一点了,室友也要睡觉了,那就留给明天实现吧。。。

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n = len(nums)
        if n==0:
            return -1
        begin = 0
        end = n-1
        pivot =  (int)((begin+end)/2)
        if nums[0]>nums[n-1]:#如果有旋转 则这个等式一定成立 否则就完全是一个递增的列表 可直接进行二分查找
            while  end > begin:#寻找旋转点
                if nums[pivot]>nums[pivot+1]:
                    break
                elif nums[pivot]>nums[end]:
                    begin = pivot
                else:
                    end = pivot
                pivot =  (int)((begin+end)/2)  
                
            if target > nums[n-1]:#目标在左上升区 设置二分查找区间
                begin = 0
                end = pivot
            else:#目标在右上升区 设置二分查找区间
                begin = pivot+1
                end = n-1
                
        current = (int)((begin+end)/2)
        while end >= begin:#进行二分查找
            if nums[current]==target:
                return current
            elif nums[current]<target:
                begin = current+1
            else:
                end = current-1
            current = (int)((begin+end)/2)
        return -1

并不是“明天”实现的,而是“后天”才实现的。。。。。

总结

第一次深夜写博客,写的很烂,思路感觉都不清晰,不过总比睁着眼睡不着觉好吧。。。
晚安,各位!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值