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

13 篇文章 0 订阅
11 篇文章 0 订阅
'''
154_寻找旋转排序数组中的最小值 II
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请找出其中最小的元素。
注意数组中可能存在重复的元素。
示例 1:
输入: [1,3,5]
输出: 1
示例 2:
输入: [2,2,2,0,1]
输出: 0
说明:

这道题是 寻找旋转排序数组中的最小值的延伸题目。
允许重复会影响算法的时间复杂度吗?会如何影响,为什么?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
'''
class Solution:
    '''
    算法1:真正的二分查找,特殊情况是nums[L] == nums[m] == nums[R],此时无法判断哪一侧是纯递增的。
    递归处理特殊情况,返回最小值,其他情况照搬无重复值循环递增数组的做法,消除了尾递归
    执行用时 :128 ms, 在所有 python3 提交中击败了5.94%的用户
    内存消耗 :29.7 MB, 在所有 python3 提交中击败了5.01%的用户
    '''
    def findMin(self, nums: list) -> int:
        def ans(L, R):
            if L + 1 == R: #单独判断只有2个元素的情形,以避免死循环
                return min(nums[L], nums[R])
            while L < R:
                m = (L + R) // 2
                if nums[L] == nums[m] == nums[R]:
                    return min(ans(L, m-1), ans(m, R))
                elif nums[m] <= nums[R]:
                    R = m
                else:
                    L = m + 1
            return nums[R]
        return ans(0, len(nums)-1)
    
    '''
    算法2:算法1的另一种写法,没有消除尾递归
    执行用时 :148 ms, 在所有 python3 提交中击败了5.94%的用户
    内存消耗 :29.7 MB, 在所有 python3 提交中击败了5.01%的用户
    '''
    def findMin2(self, nums: list) -> int:
        def ans(L, R):
            m = (L + R) // 2
            if L == R:
                return nums[L]
            elif L + 1 == R:
                return min(nums[L], nums[R])
            elif nums[L] == nums[m] == nums[R]:
                return min(ans(L, m-1), ans(m, R))
            elif nums[m] <= nums[R]:
                return ans(L, m)
            else:
                return ans(m+1, R)
        return ans(0, len(nums)-1)
    
    '''
    算法3:当nums[L] == nums[m] == nums[R]时,采用顺序查找方法,逐步缩小左边界(或者右边界),以便下一轮循环时,不再出现此种情况。
    其他情况则照搬无重复值循环递增数组的做法,实行对分查找。效率不如算法1高,但是代码更简洁。
    执行用时 :136 ms, 在所有 python3 提交中击败了5.94%的用户
    内存消耗 :29.7 MB, 在所有 python3 提交中击败了5.01%的用户
    '''
    def findMin3(self, nums: list) -> int:
        L, R = 0, len(nums)-1
        while L < R:
            m = (L + R) // 2
            if nums[L] == nums[m] == nums[R]:
                L += 1 #或R -= 1
            elif nums[m] <= nums[R]:
                R = m
            else:
                L = m + 1
        return nums[R]
    
    '''
    算法4:对算法3的条件语句做了一个顺序上的调整,也许效率更高
    执行用时 :132 ms, 在所有 python3 提交中击败了5.94%的用户
    内存消耗 :29.2 MB, 在所有 python3 提交中击败了5.01%的用户
    '''
    def findMin4(self, nums: list) -> int:
        L, R = 0, len(nums)-1
        while L < R:
            m = (L + R) // 2
            if nums[m] > nums[R]:
                L = m + 1
            elif nums[m] < nums[R]:
                R = m
            else:
                R -= 1
        return nums[R]
    
    '''
    算法5:算法3的一个变式,确保循环体内至少有3个元素,这样当nums[L] == nums[m] == nums[R]时,左右边界均可向中间移动1位,
    最后剩下2个元素,输出最小值
    执行用时 :132 ms, 在所有 python3 提交中击败了5.94%的用户
    内存消耗 :29.2 MB, 在所有 python3 提交中击败了5.01%的用户
    '''
    def findMin5(self, nums: list) -> int:
        L, R = 0, len(nums)-1
        while L + 1 < R:
            m = (L + R) // 2
            if nums[L] == nums[m] == nums[R]:
                L, R = L + 1, R - 1
            elif nums[m] <= nums[R]:
                R = m
            else:
                L = m + 1
        return min(nums[L], nums[R])
    
    '''
    算法6:对算法5的条件语句做了一个顺序上的调整,也许效率更高
    执行用时 :132 ms, 在所有 python3 提交中击败了5.94%的用户
    内存消耗 :29.2 MB, 在所有 python3 提交中击败了5.01%的用户
    '''
    def findMin6(self, nums: list) -> int:
        L, R = 0, len(nums)-1
        while L + 1 < R:
            m = (L + R) // 2
            if nums[m] > nums[R]:
                L = m + 1
            elif nums[L] == nums[m] == nums[R]:
                L, R = L + 1, R - 1
            else:
                R = m
        return min(nums[L], nums[R])
    
    
    

x = Solution()
a = [3,4,5,1,2]
print(x.findMin(a), x.findMin2(a), x.findMin3(a), x.findMin4(a), x.findMin5(a), x.findMin6(a))
a = [1,3,3]
print(x.findMin(a), x.findMin2(a), x.findMin3(a), x.findMin4(a), x.findMin5(a), x.findMin6(a))
        

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值