剑指 Offer 11. 旋转数组的最小数字
Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
1、题目📑
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为1。
实例1:
输入: [3,4,5,1,2]
输出: 1
实例2:
输入: [2,2,2,0,1]
输出: 0
注意:
- 本题与主站 154 题相同:leetcode-cn.com/problems/fi…
2、思路🧠
方法一:暴力解法
- 根据题意,第一时间想到通过暴破来解决,用变量记录当前遍历过程中遇到的最小值,在遍历结束后,返回最小值即可。
- 为什么说暴力不优雅呢,因为我们知道数组被旋转,在遍历过程中,只要有数字小于
numbers[0],那么该数字一定是最小值。
方法二:二分优化
暴力不是我们的解题目标,暴力是进不了大厂的,所以小伙伴们在做题的时候还是要想一想优化的解法熬。
- 创建两个指针 L, R 分别指向
numbers头和尾,计算出两指针之间的中间索引值 M,会出现以下三种情况: - 我们分别考虑
- M > R 时,最小值一定在 M 右侧,所以将 L 移动到 M + 1 的位置。
- M < R 时,最小值一定在 M 左侧也就是 M 的位置,所以将 R 移动到 M 的位置。
- M 既不大于 L 指针的值,也不小于 R 指针的值,意味着 M 可能等于 L 指针的值,或 R 指针的值,这时候唯一能继续进行程序的办法就是让 R 指针递减,来找最小值。
废话少说~~~~~上代码!
3、代码👨💻
第一次commit AC
class Solution {
public int minArray(int[] numbers) {
int i;
int index = 0;
for(i = 0;i < numbers.length - 1; i++){
if(numbers[i] >numbers[i + 1]) index = i + 1;
}
return numbers[index];
}
}
时间复杂度:O(n)
空间复杂度:O(1)
第二次commit AC
class Solution {
public int minArray(int[] numbers) {
int L = 0,R = numbers.length - 1;
while(L < R){
int M = L + ((R - L) >> 1);//这里是向下取整
if(numbers[M] > numbers[R]) {
L = M + 1;
}
else if(numbers[M] < numbers[R]) {
R = M;
}
else R -= 1;
}
return numbers[L];
}
}
时间复杂度:O(log n)
空间复杂度:O(1)
4、总结
该题目的使用二分查找的应用实例,首先要对二分法有所了解。
二分法模板:
public static int binarysearch(int arr[], int L, int R, int target){
int count = 0;
int M = (L + R) >> 1;
if(L > R) return -1;
if (target > arr[M]){
return binarysearch(arr, M + 1, R, target);
}else if(target < arr[M]){
return binarysearch(arr, L, M - 1, target);
}else {
return M;
}
}
❤️来自专栏《LeetCode基础算法题》欢迎订阅❤️
厂长写博客目的初衷很简单,希望大家在学习的过程中少走弯路,多学一些东西,对自己有帮助的留下你的赞赞👍或者关注➕都是对我最大的支持,你的关注和点赞给厂长每天更文的动力。
对文章其中一部分不理解,都可以评论区回复我,我们来一起讨论,共同学习,一起进步!