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

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

1. 题目描述

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

2.详细题解

    该题是153. 寻找旋转排序数组中的最小值的进阶题,在153. 寻找旋转排序数组中的最小值的基础上,将严格递增数组改为非递减数组,即允许存在相同元素,建议先尝试153. 寻找旋转排序数组中的最小值并理解后再尝试本题。

    如果不考虑 O ( l o g n ) O(log n) O(logn)的时间复杂度,直接 O ( n ) O(n) O(n)时间复杂度的扫描遍历一次即可。

    非严格升序数组,即存在相同元素的两个值。如果不旋转则最小的数值即为第一个(索引为0)的数值,数组旋转了1到n次,寻找数组中最小的元素,这道题是二分查找的变型题。

  对于严格递增的数组,假定最小值为 m i n x min_x minx,数组旋转后,假定结尾最后一个值为 t a i l tail tail,对于最小值 m i n x min_x minx,其右边的元素均小于 t a i l tail tail,而其左边的元素均大于 t a i l tail tail的值,可以利用该性质使用二分查找算法。但对于非严格递增的数组来说,由于存在相同值的情况,因此需要单独讨论。

  具体算法如下:

  • Step1:初始化:两个指针 l e f t left left 和 r i g h t right right,分别指向数组的起始和结束位置;
  • Step2:计算中间元素的索引: m i d = ( l e f t + r i g h t ) / 2 mid = (left + right) / 2 mid=(left+right)/2;
  • Step3:如果 n u m s m i d < n u m s r i g h t numsmid < numsright numsmid<numsright,说明区间 ( m i d , r i g h t ] (mid, right] (mid,right]均为最小值右边的元素,故移除,更新 r i g h t = m i d right=mid right=mid,而 m i d mid mid可能为最小值,因此更新区间时不能舍弃 m i d mid mid;
  • Step4:如果 n u m s m i d > n u m s r i g h t numsmid > numsright numsmid>numsright,说明区间 l e f t , m i d left, mid left,mid均为最小值左边的元素,故移除,更新 l e f t = m i d + 1 left=mid+1 left=mid+1,此时 m i d mid mid值不可能为最小值,因为其已经大于了结尾值,故可舍弃 m i d mid mid;
  • Step5:否则(即 n u m s m i d = n u m s r i g h t numsmid=numsright numsmid=numsright),此时难以判断是说明那个区间不包含最小值,例如 3 , 3 , 3 , 1 , 2 , 3 3 , 1 , 2 , 3 , 3 , 3 , 3 3,3,3,1,2,33,1,2,3,3,3,3 3,3,3,1,2,33,1,2,3,3,3,3,但由于此时它们的值均相同,所以无论 n u m s r i g h t numsright numsright 是不是最小值,都有一个它的「替代品」 n u m s m i d numsmid numsmid,因此可以忽略二分查找区间的右端点,更新 r i g h t − = 1 right-=1 right−=1。
  • Step6:当指针left小于right时,重复步骤Step2_Step6;
  • Step7:否则循环结束,返回 n u m s l e f t numsleft numsleft

3.代码实现

3.1 Python

python 复制代码
class Solution:
    def findMin(self, nums: List[int]) -> int:
        left, right = 0, len(nums) - 1
        while left < right:
            mid = (left + right) // 2
            if nums[mid] < nums[right]:
                right = mid
            elif nums[mid] > nums[right]:
                left = mid + 1
            else:
                right -= 1
        return nums[left]

3.2 Java

java 复制代码
class Solution {
    public int findMin(int[] nums) {
        int left = 0, right = nums.length - 1;
        while (left < right){
            int mid = (left + right)/2;
            if (nums[mid] < nums[right]){right=mid;}
            else if (nums[mid] > nums[right]){left = mid + 1;}
            else{right--;}
        }
        return nums[left];
    }
}

  执行用时不必过于纠结,对比可以发现,对于python和java完全相同的编写,java的时间一般是优于python的;至于编写的代码的执行用时击败多少对手,执行用时和网络环境、当前提交代码人数等均有关系,可以尝试完全相同的代码多次执行用时也不是完全相同,只要确保自己代码的算法时间复杂度满足相应要求即可,也可以通过点击分布图查看其它coder的code。

相关推荐
珊瑚里的鱼7 分钟前
【动态规划】打家劫舍Ⅱ
算法·动态规划
chao1898448 分钟前
SGM(Semi-Global Matching)立体匹配算法 — C++ 实现
开发语言·c++·算法
MageGojo14 分钟前
天气 API 接入实战:基于 ApiZero 实现实时天气、分钟级降水和 15 天预报查询
java·后端·spring·api 接口接入·接口实战
黎阳之光24 分钟前
数智赋能水厂全链路安全|黎阳之光以视频孪生技术落地供水精细化管控
人工智能·物联网·算法·安全·数字孪生
YXWik635 分钟前
图片 OCR 文字提取 (Python + AI 模型(ModelScope))
人工智能·python·ocr
自动跟随36 分钟前
UWB自动跟随技术全栈解析:从定位算法到“位控一体化“
java·网络·人工智能
喜欢打篮球的普通人42 分钟前
LLVM 后端流程与关键数据结构:从 IR 到机器码的入门笔记
java·数据结构·笔记
弹简特1 小时前
【Java项目-轻聊】07-实现主页面模块
java·开发语言
NOVAnet20231 小时前
AI 全球化部署网络瓶颈:算法模型跨地域、跨云互联核心痛点解析
算法·ai·sd-wan·专线·跨区域
wuminyu1 小时前
Java锁机制之轻量级锁判断与尝试逻辑源码剖析
java·linux·c语言·jvm·c++