首页 > 试题广场 >

旋转数组的最小数字

[编程题]旋转数组的最小数字
  • 热度指数:1385475 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

数据范围:,数组中任意元素的值: 
要求:空间复杂度: ,时间复杂度:
示例1

输入

[3,4,5,1,2]

输出

1
示例2

输入

[3,100,200,3]

输出

3
推荐
思路

剑指Offer中有这道题目的分析。这是一道二分查找的变形的题目。


旋转之后的数组实际上可以划分成两个有序的子数组:前面子数组的大小都大于后面子数组中的元素

注意到实际上最小的元素就是两个子数组的分界线。本题目给出的数组一定程度上是排序的,因此我们试着用二分查找法寻找这个最小的元素。

思路:

(1)我们用两个指针left,right分别指向数组的第一个元素和最后一个元素。按照题目的旋转的规则,第一个元素应该是大于最后一个元素的(没有重复的元素)。

但是如果不是旋转,第一个元素肯定小于最后一个元素。

(2)找到数组的中间元素。

中间元素大于第一个元素,则中间元素位于前面的递增子数组,此时最小元素位于中间元素的后面。我们可以让第一个指针left指向中间元素。

移动之后,第一个指针仍然位于前面的递增数组中。

中间元素小于第一个元素,则中间元素位于后面的递增子数组,此时最小元素位于中间元素的前面。我们可以让第二个指针right指向中间元素。

移动之后,第个指针仍然位于面的递增数组中。

这样可以缩小寻找的范围。

(3)按照以上思路,第一个指针left总是指向前面递增数组的元素,第二个指针right总是指向后面递增的数组元素。

最终第一个指针将指向前面数组的最后一个元素,第二个指针指向后面数组中的第一个元素。

也就是说他们将指向两个相邻的元素,而第二个指针指向的刚好是最小的元素,这就是循环的结束条件。

到目前为止以上思路很耗的解决了没有重复数字的情况,这一道题目添加上了这一要求,有了重复数字。

因此这一道题目比上一道题目多了些特殊情况:

我们看一组例子:{1,0,11,1} 和 {1,1, 1,0,1} 都可以看成是递增排序数组{0,1,1,1,1}的旋转。

这种情况下我们无法继续用上一道题目的解法,去解决这道题目。因为在这两个数组中,第一个数字,最后一个数字,中间数字都是1。

第一种情况下,中间数字位于后面的子数组,第二种情况,中间数字位于前面的子数组。

因此当两个指针指向的数字和中间数字相同的时候,我们无法确定中间数字1是属于前面的子数组(绿色表示)还是属于后面的子数组(紫色表示)。

也就无法移动指针来缩小查找的范围。

代码
#include <iostream>
#include <vector>
#include <string>
#include <stack>
#include <algorithm>
using namespace std;

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        int size = rotateArray.size();
        if(size == 0){
            return 0;
        }//if
        int left = 0,right = size - 1;
        int mid = 0;
        // rotateArray[left] >= rotateArray[right] 确保旋转
        while(rotateArray[left] >= rotateArray[right]){
            // 分界点
            if(right - left == 1){
                mid = right;
                break;
            }//if
            mid = left + (right - left) / 2;
            // rotateArray[left] rotateArray[right] rotateArray[mid]三者相等
            // 无法确定中间元素是属于前面还是后面的递增子数组
            // 只能顺序查找
            if(rotateArray[left] == rotateArray[right] && rotateArray[left] == rotateArray[mid]){
                return MinOrder(rotateArray,left,right);
            }//if
            // 中间元素位于前面的递增子数组
            // 此时最小元素位于中间元素的后面
            if(rotateArray[mid] >= rotateArray[left]){
                left = mid;
            }//if
            // 中间元素位于后面的递增子数组
            // 此时最小元素位于中间元素的前面
            else{
                right = mid;
            }//else
        }//while
        return rotateArray[mid];
    }
private:
    // 顺序寻找最小值
    int MinOrder(vector<int> &num,int left,int right){
        int result = num[left];
        for(int i = left + 1;i < right;++i){
            if(num[i] < result){
                result = num[i];
            }//if
        }//for
        return result;
    }
};

int main(){
    Solution s;
    //vector<int> num = {0,1,2,3,4,5};
    //vector<int> num = {4,5,6,7,1,2,3};
    vector<int> num = {2,2,2,2,1,2};
    int result = s.minNumberInRotateArray(num);
    // 输出
    cout<<result<<endl;
    return 0;
}
编辑于 2015-08-18 23:34:39 回复(141)
使用Java暴力破解:
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
    public int minNumberInRotateArray (int[] nums) {
        // write code here
        if (nums.length == 0)
            return 0;
        //假设第一个元素是最小的
        int min = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] < min)
                // 如果找到更小的元素,则更新最小值
                min = nums[i];
        }
        return min;
    }
}


编辑于 2024-04-11 10:53:53 回复(0)
import java.util.*;
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
    public int minNumberInRotateArray (int[] nums) {
        // if(nums.length==1||nums[0]==nums[nums.length-1]){
        //     return nums[0];
        // }
        int l = 0;
        int r = nums.length - 1;
        while (l <= r) {
            int mid = (l + r) / 2;
            if (l == r) {
                return nums[r];
            }
            if (nums[mid] > nums[r])
                l = mid + 1;
            else if (nums[mid] == nums[r]) {
                if ((mid + 1 <= nums.length - 1) && nums[mid + 1] != nums[mid]) {
                    l = mid + 1;
                } else {
                    r = mid;
                }
            } else {
                r = mid;
            }
        }
        //走不到这,写着为了不标红,看着心烦
        return -1;
    }
}
编辑于 2024-04-06 20:54:09 回复(1)
import java.util.*;

public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型一维数组
* @return int整型
*/
public static int minNumberInRotateArray (int[] nums) {
int l=nums.length;
if (nums[0]<nums[l-1]){
return nums[0];
}
int s=0;
int e=l-1;
while (nums[0]==nums[e]){
e--;
}
while (s<e){
int mid=(s+e)/2;
if (nums[mid]>nums[e]){
s=mid+1;
}else {
e=mid;
}
}
return nums[s];
}
}
编辑于 2024-04-04 17:52:59 回复(1)
有没有大佬看出其中的错误,总感觉不是很对
public int minNumberInRotateArray (int[] nums) {
        // write code here
        int c=1;
        if(nums.length==0){
            return 0;
        }
        for(int i=0;i<nums.length-1;i++){
            if(nums[i]>nums[i+1]){
                c= nums[0]>nums[i+1]?nums[i+1]:nums[0];
            }
        }
        return c>nums[nums.length-1]?nums[nums.length-1]:c;
    }
发表于 2024-03-27 21:04:54 回复(1)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int minNumberInRotateArray (int[] nums) {
        // 这里可以将数组分解为两部分
        // 这两部分均为 从小到大排序的数组,以 12345 为例
        // 会有 34512、45123 等

        // write code here
        // 先来判断一下数组为空的情况
        if(nums.length == 0) {
            return 0;
        }

        // 使用二分法来解决
        int start = 0;
        int end = nums.length - 1;
        // 这里是旋转数组,先来考虑第一种情况
        // 当这里的第一个元素的值 比 最后一个元素的值小
        // 对于上面的例子,可以断定这里的第一个值 就一定是 最小值
        if(nums[start] < nums[end]) {
            return nums[start];
        }

        // 之后通过 二分法来判断最小值
        // 先来说明没有重复值的情况
        // 不断的通过 左、右 侧加逼 
        // 最终会使得 start 在左侧部分的最大值(最后一个位置) 上
        // 并且会使得 end 在右侧部分上达到其中的 最小值(这个就是我们需要的值)
        // 此时 start 和 end 就是一个相邻的关系,所以对于 while 设定这样一个判断条件
        while(start != end-1) {
            int mid = (start + end) / 2;
            // 在这之中还需要处理多个重复数据的情况,并且处理三个指针重叠后的情况
            // 如题例:1,0,1,1,1
            if(nums[start] == nums[end] && nums[start] == nums[mid]) {
                // 这里定义一个方法专门来处理这个问题
                return minNum(nums,start,end);
            }
            if(nums[mid] >= nums[start]) {
                start = mid;
            }else if(nums[mid] <= nums[end]){
                end = mid;
            }
        }
        // 在完成上面的判断后,这里的 end 位置的值就是我们要找到的最小值
        return nums[end];
    }

    private int minNum(int[] nums, int start, int end) {
        // 这里需要注意的是,要将值设置为 当前重合处的值,不能设置为 0 !!!
        int re = nums[start];
        for (int i=0; i < nums.length; i++) {
            if(re > nums[i]) {
                // 将这里的最小值记录下来并返回
                re = nums[i];
            }
        }
        return re;
    }
}

发表于 2024-03-23 11:00:30 回复(0)
public int minNumberInRotateArray (int[] nums) {
        // write code here
        if(nums.length <= 0){
            return 0;
        }
        int rt = nums[0];
        for(int info : nums){
            if(rt > info){
                rt = info;
            }
        }
        return rt;
    }

不考虑二分是不是更快?

发表于 2024-03-14 02:15:43 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
    public int minNumberInRotateArray (int[] nums) {
        // write code here
        return binary(nums, 0, nums.length - 1);
    }

    public int binary(int[] nums, int left, int right) {
        if (left >= right || nums[left] < nums[right]) {
            return nums[left];
        }
        int mid = left + (right - left) / 2;
        int leftNum = binary(nums, left, mid);
        int rightNum = binary(nums, mid + 1, right);
        return leftNum <= rightNum ? leftNum : rightNum;
    }

}


发表于 2023-12-13 14:19:10 回复(0)
import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
    public int minNumberInRotateArray (int[] nums) {
        // write code here
        if(nums.length==0){
            return 0;
        }
        int ans = nums[0];
            for(int i=0;i<nums.length;i++){
                ans=Math.min(ans,nums[i]);
             
        }
        return ans;
    }
}
发表于 2023-10-29 18:37:23 回复(0)
 
public int minNumberInRotateArray (int[] nums) {
        // write code here
        int min=nums[0];
        for(int i=1;i<nums.length;i++){
            if(min>nums[i]){
                min=nums[i];
            }
        }
        return min;
    }
发表于 2023-10-26 15:38:12 回复(2)
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int minNumberInRotateArray (int[] nums) {
        // write code here
        a(nums,0,nums.length-1);
        return nums[0];
    }
    public void a(int[] nums,int left,int right){
        if(left>=right)
            return;
        int mid=(left+right)/2;
        a(nums,left,mid);
        a(nums,mid+1,right);
        b(nums,left,mid,right);
    }
     public void b(int[] nums,int left,int mid,int right){
        if(nums[left]>nums[mid+1]){
            nums[left]=nums[mid+1];
        }
    }
}

发表于 2023-10-09 16:45:37 回复(0)
啥旋转啊,没看懂,不是这样就好了吗,直接过了啊
        Arrays.sort(nums);
        return nums[0];


发表于 2023-09-18 11:16:38 回复(2)
    public int minNumberInRotateArray (int[] nums) {
        int minVal = findMinVal(nums, 0, nums.length - 1); // 分治算法
        return minVal;
    }
    private int findMinVal(int[] nums, int l, int r) {
        if (l == r) {
            return nums[l];
        }
        if (nums[l] < nums[r]) {
            return nums[l];
        }
        int c = (l + r) / 2;
        int minVal01 = findMinVal(nums, l, c);
        int minVal02 = findMinVal(nums, c + 1, r);
        return minVal01 < minVal02 ? minVal01 : minVal02;
    }
发表于 2023-09-16 21:52:28 回复(0)
    public int minNumberInRotateArray (int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        for (int i = 0; i < nums.length; i++) {
            if (i == nums.length - 1) {
                return nums[0];
            }
            if (nums[i + 1] < nums[i]) {
                return nums[i + 1];
            }
        }
        return 0;
    }
以上代码亦可通过测试,是否可以视为一种解题方式

发表于 2023-09-13 22:29:51 回复(0)
import java.util.*;


public class Solution {
    //揪出L,M,R都相等的情况,然后就能二分
    //但是,[M]不能和[L]去对比,因为不一定就是旋转过的.
    //在旋转过的情况下, [L] > [M], 确实应该去右边二分
    //但是这种本来就有序的例子:[1, 2, 3, 4, 5, 6]就过不了
    //所以只能让[M]和[R]去比,
    //[M] > [R], 只有一种可能,转折点在右边,所以去右边二分
    //[M] < [R], 去左边二分,会发现不管是不是旋转过,都是对的
    //最后,返回的应该是[L], [R]中小的那个
    //还是因为可能本来就有序,
    //如果旋转过,L一定指向左子数组最后,R一定是右子数组最开始,那么返回R没错
    //如果本来有序,就会发现是不对的
    public int minNumberInRotateArray (int[] nums) {
        // write code here
        int L = 0, R = nums.length - 1, M = 0;
        int min = nums[M];
        while (L <= R) {
            M = L + ((R - L) >> 1);
            if (R - L == 1) {
                // M = R;
                break;
            }
            if (nums[L] == nums[M] && nums[M] == nums[R]) {
                while (R > L && nums[R - 1] == nums[R]) {
                    R--;
                }
                //L == M || [L] != [L + 1]
                if (R == L) {
                    return nums[R];
                } else {
                    R = R - 1;
                    continue;
                }
            }
            if (nums[M] > nums[R]) {
                L = M;
            } else {
                R = M;
            }

        }
        return Math.min(nums[L], nums[R]);
    }
}
这题在leetcode上是hard,这里居然是简单,卧槽
发表于 2023-06-29 21:03:08 回复(0)
import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        int min = Integer.MAX_VALUE;
        for(int arr : array){
            min = Math.min(min,arr);
        }
        return min;
    }
}

发表于 2023-06-14 10:50:20 回复(0)
public int minNumberInRotateArray(int [] array) {
        int left=0;
        int right=array.length-1;
        //删除重复元素
        while(left!=right&&array[left]==array[right]){
            right--;
        }
        if(left==right||array[left]<array[right]){
            return array[left];
        }
        int num=array[left];
        while(left!=right){
            int mid=left+(right-left)/2;
            if(array[mid]>=num){//比基准大,往右走
                left=mid+1;
            }else{
                right=mid;//这里为什么不是mid-1
            }
        }
        return array[right];
    
    }

发表于 2023-05-27 21:55:48 回复(0)
import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {

        //1. 暴力破解
        int min = 0 ;
        int temp = 0;
        int max =  Integer.MIN_VALUE;
        for (int i = 0; i < array.length - 1; i++) {
            if (array[i] < array[i + 1]) {
                min = array[i];
            } else {
                min = array[i + 1];
            }
            //初始化
            if (i == 0) {
                temp = min;
            }
            if (min < temp) {
                temp = min;
            }
        }
        return temp;
    }
    //     //2.二分法 不能使用, 不是有序的数组
    //     // int min = 0 ;
    //     // int temp = 0;
    //     // for (int i = 0; i < array.length - 1; i++) {
    //     //     if (array[i] < array[i + 1]) {
    //     //         min = array[i];
    //     //     } else {
    //     //         min = array[i + 1];
    //     //     }
    //     //     //初始化
    //     //     if (i == 0) {
    //     //         temp = min;
    //     //     }
    //     //     if (min < temp) {
    //     //         temp = min;
    //     //     }
    //     // }


    //     int min = 0 ;
    //     int temp = 0;
    //     int start = 0;
    //     int end = array.length - 1;
    //     int mid = 0;
    //     while (start < end) {
    //         mid = (start + end) / 2;
    //         if (array[mid] > array[end]) {
    //             min = array[end];
    //             end++;
    //         } else if (array[mid] > array[start]) {
    //             min = array[start];
    //             start++;
    //         } else {
    //             min = array[mid];
    //         }
    //         //初始化
    //         if (min < temp) {
    //             temp = min;
    //         }
    //     }
    //     return temp;
    // }
}


发表于 2023-05-06 18:17:53 回复(0)

问题信息

难度:
418条回答 277338浏览

热门推荐

通过挑战的用户

查看代码