11-旋转数组的最小数字
来源:力扣(LeetCode)
链接: https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers
,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2]
为 [1,2,3,4,5]
的一次旋转,该数组的最小值为 1。
注意,数组 [a[0], a[1], a[2], ..., a[n-1]]
旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]
。
示例 1:
输入:numbers = [3,4,5,1,2]
输出:1
示例 2:
输入:numbers = [2,2,2,0,1]
输出:0
提示:
n == numbers.length
1 <= n <= 5000
-5000 <= numbers[i] <= 5000
numbers
原来是一个升序排序的数组,并进行了1
至n
次旋转
解法
本题是求解列表中最小的元素,初步想法有使用库函数,迭代遍历,但是本题有说明该数组是一个有序数组,只是通过了旋转操作,但是旋转后的数组,部分仍然是有序的,只不过分为了前半段有序以及后半段有序,对于有序数组中元素的查找,可以使用二分查找法;
- 自带的库函数
- 迭代:设定初始最小值为数组的第一个元素,然后遍历数组,挨个进行比较,如果比最小值要小,更新最小值
- 二分查找法:对于旋转后的数组,肯定是有序的数组,要么是按照原来的一样(最小值元素为第一个),要么就是分段有序。左边上升,右边也上升,只是到中间某个点不上升,中间的那个点即为最小值。使用二分查找判断mid落在哪个范围内;
- 如果nums[mid] > nums[right], 则表明mid落在了左半段,left要右移,left=mid+1
- 如果nums[mid] < nums[right], 则表明mid落在了右边段,right要左移, right = mid
- 如果nums[mid] == nums[right], 这个时候无法进行判别,但是既然数组中已经有了一个元素与最右边元素相同,那么去掉最右边元素并不影响最终的结果,因此,right = right-1
代码实现
迭代遍历方法:
- python实现
class Solution:
def minArray(self, numbers: List[int]) -> int:
# return min(numbers)
min_val = numbers[0]
for i in numbers[1:]:
if i < min_val:
min_val = i
return min_val
- c++实现
class Solution {
public:
int minArray(vector<int>& numbers) {
int min_val = numbers[0];
for(int num: numbers)
{
if(num < min_val)
{
min_val = num;
}
}
return min_val;
}
};
二分查找方法:
- python实现
class Solution:
def minArray(self, numbers: List[int]) -> int:
# 二分查找
left = 0
right = len(numbers) - 1
while left < right:
mid = left + (right-left) // 2
if numbers[mid] > numbers[right]:
left = mid+1
elif numbers[mid] < numbers[right]:
right = mid
else:
right -= 1 # 如果相等的时候,不能确定位于前半部分还是后半部分,但是可以将右边-1
return numbers[left]
- c++实现
class Solution {
public:
int minArray(vector<int>& numbers) {
int length = numbers.size();
int left = 0;
int right = length-1;
while(left < right)
{
int mid = left + (right-left) / 2;
if(numbers[mid] < numbers[right])
{
right = mid;
}
else if(numbers[mid] > numbers[right])
{
left = mid + 1;
}
else
{
right--;
}
}
return numbers[left];
}
};
复杂度分析
- 时间复杂度: 迭代 O ( n ) O(n) O(n), 二分查找 o ( l o g n ) o(logn) o(logn)
- 空间复杂度:O(1)$