目录
一、题目描述
描述:
有一个长度为 n 的非降序数组,比如[1,2,3.4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围: 1 <= n <= 10000,数组中任意元素的值: 0 <= val <= 10000要求: 空间复杂度: 0(1),时间复杂度: (logn)
示例:
输入:[3,4,5,1,2]
返回值:1
二、题解
1.分析
核心思想:通过不断缩小搜索范围,利用二分查找的方式快速找到旋转排序数组中的最小值。它的时间复杂度为O(logN),其中N是数组的长度。
具体步骤如下:
(1)定义两个指针, left
和 right
,分别指向数组的最左端和最右端。
(2)进入循环,判断条件是 left
小于 right
,即搜索范围还没有缩小到只剩一个元素。
(3)在循环中,计算中间位置 mid
,通过将 left
和 right
相加再除以2得到。
(4)判断中间位置的值 nums[mid]
和右边界的值 nums[right]
的大小关系。
(5)如果 nums[mid]
大于 nums[right]
,说明最小值在中间位置的右侧,将 left
移动到 mid
的右侧一位。
(6)如果 nums[mid]
小于 nums[right]
,说明最小值在中间位置的左侧或者就是中间位置本身,将 right
移动到 mid
的位置。
(7)如果 nums[mid]
等于 nums[right]
,无法确定最小值在哪一侧,但可以确定的是,由于存在重复元素,可以将右边界向左移动一位。
(8)循环结束后,返回 nums[left]
作为最小值。
2.代码
代码如下:
public static int fincMinNumber(int[] nums){
int left = 0; // 左边界
int right = nums.length-1; // 右边界
while (left<right){
int mid = (left+right)/2; // 中间位置
if (nums[mid]>nums[right]) // 如果中间位置的值大于右边界的值
left=mid+1; // 将左边界移动到中间位置的右侧
else if(nums[mid]<nums[right]) // 如果中间位置的值小于右边界的值
right=mid; // 将右边界移动到中间位置
else
right--; // 如果中间位置的值等于右边界的值,则将右边界向左移动一位
}
return nums[left]; // 返回最小值
}