【剑指offer】9. 旋转数组的最小数字(java)

news/2024/11/29 0:37:12/

文章目录

  • 旋转数组的最小数字
    • 描述
    • 示例1
    • 示例2
    • 思路
    • 完整代码

旋转数组的最小数字

描述

有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

数据范围: 1 ≤ n ≤ 10000 1≤n≤10000 1n10000,数组中任意元素的值: 0 ≤ v a l ≤ 10000 0≤val≤10000 0val10000

要求:空间复杂度: O ( 1 ) O(1) O(1) ,时间复杂度: O ( l o g n ) O(logn) O(logn)

示例1

输入:

[3,4,5,1,2]

返回值:

1

示例2

输入:

[3,100,200,3]

返回值:

3

思路

第一个很容易想到的办法就是遍历,每次都将当前元素和下一个元素相比,如果后一个小于前一个,则说明后一个元素为原数组的最小元素。

代码为:

int result = nums[0];
for (int i = 0; i < nums.length - 1; i++) {if (nums[i + 1] < nums[i]) {result = nums[i + 1];break;}
}
return result;

但在这种情况下,最坏情况可能需要遍历n次,即时间复杂度为 O ( n ) O(n) O(n),而题目要求为 O ( l o g n ) O(logn) O(logn)

其实看到 O ( l o g n ) O(logn) O(logn) 基本可以知道思路为二分法

基本思路是:

  • 每次定义数组的左右边界left和right,初始化为0和num.length-1
  • 然后每次循环都取出中间元素,并将中间元素和左边界元素比较
  • 如果大于等于说明左边都是非递减序列,那么要找的最小值肯定在中间和右边界之间
  • 相反如果小于则说明最小值肯定在左边界和中间之间

例:

假设输入为[3,4,5,1,2],初始化left=0,right=4,则mid=2此时nums[0]<nums[2],所以更新left为2,更新后的mid为3,此时nums[2]>nums[3],说明找到了最小元素,输出即可

一开始我写的是:

if (nums.length == 0) {return 0;
}
int left = 0;
int right = nums.length - 1;
while (left < right - 1) {int mid = (left + right) / 2;if (nums[mid] >= nums[left]) {left = mid;} else if (nums[mid] <= nums[right]) {right = mid;}
}
return nums[right];

但是当遇到某些特殊的输入值时结果不正确,比如[1,0,1,1,1]

然后后面修改了很多但一直没过,直到看到别人的解法才发现自己陷入了老是将中间值和左右值比较,但实际上只需将中间值最右值比较即可,只有三种情况:

  • 中间值小于最右值:说明右半边是非递减序列,则最小值应该在左半边
  • 中间值大于最右值:说明右半边不是非递减序列,则最小值应该在右半边
  • 如果等于,则说明无法判断,应该将right往左移
if (nums.length == 0) {return 0;
}
int left = 0;
int right = nums.length - 1;
while (left < right) {int mid = left + (right - left) / 2;if (nums[mid] > nums[right]) {left = mid + 1;} else if (nums[mid] < nums[right]) {right = mid;} else {right--;}
}
return nums[left];

这里 left=mid+1 的原因是因为 nums[mid] > nums[right],则说明 num[mid] 肯定不是最小的,所以左边界应该在其 mid 的下一位

举个例子,比如输入为[3,4,5,1,2],此时 nums[mid]=5nums[right]=2 ,并且 nums[mid] > nums[right],那么 nums[mid] 肯定不会是最小的,需要往右移一位。

同理,right = mid 的原因是因为对于下面这种输入时 [4,5,1,2,3],此时 nums[mid]=1nums[right]=3 ,并且 nums[mid] < nums[right],如果说是right = mid - 1 的话会导致 mid 值没判断是不是最小的,可能会错过最终结果

完整代码

import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*** @param nums int整型一维数组* @return int整型*/public int minNumberInRotateArray (int[] nums) {// write code hereif (nums.length == 0) {return 0;}int left = 0;int right = nums.length - 1;while (left < right) {int mid = left + (right - left) / 2;if (nums[mid] > nums[right]) {left = mid + 1;} else if (nums[mid] < nums[right]) {right = mid;} else {right--;}}return nums[left];}
}

http://www.ppmy.cn/news/786704.html

相关文章

RabbitMQ系列(29)--RabbitMQ搭建Shovel

前言&#xff1a; Federation具备的数据转发功能类似&#xff0c;Shovel能够可靠、持续地从一个Broker中的队列(作为源端&#xff0c;即source)拉取数据并转发至另一个Broker中的交换器(作为目的端&#xff0c;即destination)。作为源端的队列和作为目的端的交换器可以同时位于…

AUTOSAR从入门到精通-【应用篇】基于 AUTOSAR 的四轮驱动客车整车控制器应用层软件开发研究

目录 前言 国内研究现状 国外研究现状 基于 AUTOSAR 的整车控制器应用层软件设计

惠普笔记本拆机详细步骤

第一次拆电脑&#xff0c;拆着玩玩&#xff0c;非也&#xff0c;拆机原因一&#xff1a;本人笔记本两个小喇叭&#xff0c;结果一个正常声&#xff0c;一个破音了&#xff0c;不管把声音调大还是调小&#xff0c;这破音的效果依然不减&#xff0c;把声音出孔堵住听着舒服点....…

笔记本拆装步骤及注意事项

笔记本拆装步骤及注意事项 一、首先清理桌面 保持桌面的干净整洁&#xff0c;以免和其它笔记本配件混淆和刮花笔记本机壳。 二、笔记本按机壳可分四大部分&#xff1a; ①A壳&#xff1a;笔记本未打开的时候&#xff0c;最上面的那面。 ②B壳&#xff1a;笔记本打开后与液晶屏同…

Goland相关

前言 老版本的goland 在gui界面无法打开插件市场列表。整个时候需要手动去官网下载。再次点gui界面就能检测到进行自动安装了。 离线安装插件 ## 参考文章 https://cloud.tencent.com/developer/article/2056411?areaSource102001.16&traceIdYG1NTJjJBy8IdKLPsj731## …

【编译原理】语法分析程序设计-用表驱动的预测分析法进行语法分析(C++)

目录 一、实验目的二、实验内容三、实验原理及步骤四、源代码(包含完整注释)五、运行结果分析六、总结一、实验目的 理解语法分析器的任务和工作原理;掌握计算机语言语法分析程序的设计方法,使用某种高级编程语言实现其语法分析器。 二、实验内容 对于只含有 +、* 运算的算…

电脑把计算机用户删了怎么办,电脑密码忘了怎么办最简单的方法

1、启动计算机&#xff0c;在启动画面出现后马上按下F8键&#xff0c;选择【带命令行的安全模式】&#xff1b; 2、运行过程结束时&#xff0c;系统列出了系统超级用户【administrator】和本地用户【你以前的用户名】的选择菜单&#xff0c;鼠标单击【administrator】&#xff…

mac电脑忘记mysql密码怎么办?

1. 苹果->系统偏好设置->最下边点mysql 在弹出页面中 关闭mysql服务(点击stop mysql server) 1-1.如果安装时&#xff0c;没有界面版&#xff0c;第一步可省略。 2. 进入终端输入&#xff1a;cd /usr/local/mysql/bin/ 2-1.此处输出的是你的mysql的安装位置&#xff0c;…