首页 > 其他分享 >Leetcode 154. 寻找旋转排序数组中的最小值 II

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

时间:2024-09-27 14:46:51浏览次数:1  
标签:right 154 指向 nums mid II target Leetcode left

1.题目基本信息

1.1.题目描述

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到:

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,4]
  • 若旋转 7 次,则可以得到 [0,1,4,4,5,6,7]
    注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

给你一个可能存在 重复 元素值的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须尽可能减少整个过程的操作步骤。

1.2.题目地址

https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array-ii/description/

2.解题方法

2.1.解题思路

二分查找(红蓝染色法)

2.2.解题步骤

第一步,确定红蓝染色的两个特征。不变特征:1.红色始终标记在小于target的指针位置(target这里为目标求的最小索引),蓝色始终标记大于等于target的指针位置;2.左闭右闭,left-1始终指向红色,right始终指向蓝色(这里和普通的二分情况有所不同,right从一开始就属于蓝色阵营)

第二步,使用左闭右闭区间的模板处理。mid取中位数的下位整数,如果mid指向的值大于right指向的值,mid一定小于target,标记mid处为红色,即left更新为mid+1。如果小于right指向的值,则一定在右非递减区间,但是这里的right不能更新为mid-1,因为mid-1可能是红色区域,但是right不能指向红色区域,所以将right更新mid处。如果right和mid处值相等,此时mid可能是红色区域也可能是蓝色区域,所以right自减1是最保险的策略。最后直到left大于right退出循环。

第三步,经过上面的循环,由于left-1指向最后一个红色位置的特征,所以left一定指向target,返回nums[left]即为最终结果。

注意:这里如果nums[mid] < nums[right]的情况不好处理,可以去掉这一步的判断,在nums[mid] <= mid[right]时,直接right自减1,一样能AC,且结果差不了多少。这种做法可以参考下面的C++代码。

3.解题代码

Python代码

class Solution:
    # 特点:right处的值在右边的非递减区间总是最大的,但是比左边的非递减区间的值都要小。根据这个特征就可以进行二分法求解。
    # 第一步,确定红蓝染色的两个特征。不变特征:1.红色始终标记在小于target的指针位置(target这里为目标求的最小索引),蓝色始终标记大于等于target的指针位置;2.左闭右闭,left-1始终指向红色,right始终指向蓝色(这里和普通的二分情况有所不同,right从一开始就属于蓝色阵营)
    # 第二步,使用左闭右闭区间的模板处理。mid取中位数的下位整数,如果mid指向的值大于right指向的值,mid一定小于target,标记mid处为红色,即left更新为mid+1。如果小于right指向的值,则一定在右非递减区间,但是这里的right不能更新为mid-1,因为mid-1可能是红色区域,但是right不能指向红色区域,所以将right更新mid处。如果right和mid处值相等,此时mid可能是红色区域也可能是蓝色区域,所以right自减1是最保险的策略。最后直到left大于right退出循环。
    # 第三步,经过上面的循环,由于left-1指向最后一个红色位置的特征,所以left一定指向target,返回nums[left]即为最终结果。
    # 注意:这里如果nums[mid]<nums[right]的情况不好处理,可以去掉这一步的判断,在nums[mid]<=mid[right]时,直接right自减1,一样能AC,且结果差不了多少。
    def findMin(self, nums: List[int]) -> int:
        left,right=0,len(nums)-1
        while left<=right:
            mid=(right-left)//2+left
            if nums[mid]>nums[right]:
                left=mid+1
            elif nums[mid]<nums[right]:
                right=mid   # mid-1可能会跳到左非递减区间,所以不可以
            else:   # 相等的时候不能盲目二分,mid可能是红色阵营也可能是蓝色阵营,所以让right自减1即可
                right-=1
        return nums[left]

C++代码

class Solution {
public:
    int findMin(vector<int>& nums) {
        int length=nums.size();
        int left=0,right=length-1;
        while(left<right){
            int mid=(right-left)/2+left;
            if(nums[mid]>nums[right]){
                left=mid+1;
            }else{
                right--;
            }
        }
        return nums[left];
    }
};

4.执行结果

在这里插入图片描述

标签:right,154,指向,nums,mid,II,target,Leetcode,left
From: https://www.cnblogs.com/geek0070/p/18435705

相关文章

  • 【LeetCode Hot 100】21. 合并两个有序链表
    题目描述最简单粗暴的想法是将两个链表的所有元素拿出来放在一个数组中,再将此数组排序,最后生成一个新链表并返回。由于给出的参数本身就是两个排好序的链表,可以进行一次遍历,就能保证元素仍然是有序的:每次比较当前指针指向的两个元素的大小,较小的拿出来作为当前元素并将指针向前移......
  • LeetCode刷题日记之二叉树(二)
    目录前言左叶子之和找树左小角的值总结前言经过数模比赛的四天忙碌后博主继续开始LeetCode学习了,给大家分享学习心路的同时也是在不断勉励自己每天把自己的学的东西去进行一个产出记录,不足的地方欢迎大家批评指正,一起加油吧朋友们!......
  • 410. 分割数组的最大值(leetcode)
    https://leetcode.cn/problems/split-array-largest-sum/description/比较难的二分,关键点在于看出二段性,段数越多最大值越小,段数越小最大值越大,二分最大值,然后就是最大值的合法性校验(判断段数<=k),用于二分的checkclassSolution{publicintsplitArray(int[]n......
  • 【leetcode】2. 两数相加
      总体思路:1.将两个链表里的数字相加:总左往右加,存入第三方链表L3里;2.设置一个进位符t,用来存储每位相加的进位信息;3.对多出来单独的链表进行处理(只需考虑进位),接入到L3的后面。/***Definitionforsingly-linkedlist.*structListNode{*intval;*s......
  • Windows Server 2019 Web服务器之IIS的安装与基本配置
    准备工作:选择一台服务器作为WEB-IIS服务器在WindowsServer2019系统中,IIS角色是可选组件,默认情况下是没有安装的。1.在windows服务器中安装IIS1)打开【服务器管理器】,单击【添加角色和功能】。2)默认选择【基于角色或基于功能的安装】,点击【下一步】。3)默认选项,继续下一步。......
  • 【LeetCode Hot 100】20. 有效的括号
    题目描述这个题目在讲解栈的应用的时候是常用的例子,在遍历括号串的时候维护一个栈结构,如果当前字符是前括号,暂时没有与之配对的后括号,则先将其压入栈中。C++STL和Java都提供了对应的容器,但是由于我们知道栈的大小不可能超过括号串的长度,所以也可以手动用数组模拟,这样运行速度可......
  • 洛谷每日一题(P1540 [NOIP2010 提高组] 机器翻译)
    原题目链接:P1540[NOIP2010提高组]机器翻译-洛谷|计算机科学教育新生态(luogu.com.cn)原题目截图:思路分析:读懂题意,直接模拟过程即可。这是一道很简单的题目。思路过程很类似模拟页面置换算法中的先进先出(FIFO)策略。因此我们很容易想到,要用队列来实现。下面是......
  • leetcode每日一题day15(24.9.25)——公司命名
    思路:首先如果没有相同的后缀,则无论只要不是相同的首字母交换都不会出现重复情况,如果有重复后缀,则还需多增加个不能和,首字符与另一相同后缀字串的首字符相同的字串交换。主要矛盾已经明确,则可对矛盾进行分析。首先把范围缩小到只有两种不同首字母,对于这种情况      ......
  • 2024.9.25 Python,单词替换,优美的排列 II,sort的用法前K个高频单词,广度优先搜索腐烂的橘
    1.单词替换在英语中,我们有一个叫做词根(root)的概念,可以词根后面添加其他一些词组成另一个较长的单词——我们称这个词为衍生词(derivative)。例如,词根help,跟随着继承词“ful”,可以形成新的单词“helpful”。现在,给定一个由许多词根组成的词典dictionary和......
  • Leetcode 622. 设计循环队列
    1.题目基本信息1.1.题目描述设计你的循环队列实现。循环队列是一种线性数据结构,其操作表现基于FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列......