剑指:旋转数组的最小数字

旋转数组的最小数字

题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

输入一个升序的数组的一个旋转,输出旋转数组的最小元素。

例如数组 {3,4,5,1,2} 为 {1,2,3,4,5} 的一个旋转,该数组的最小值为 1。

数组可能包含重复项。

注意:数组内所含元素非负,若数组大小为 0,请返回 -1。

样例

输入:nums=[2,2,2,0,1]

输出:0

解法

解法一

直接遍历数组找最小值,时间复杂度 O(n),不推荐。

class Solution {

    /**
     * 获取旋转数组的最小元素
     *
     * @param nums 旋转数组
     * @return 数组中的最小值
     */
    public int findMin(int[] nums) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int min = nums[0];
        int n = nums.length;
        if (min < nums[n - 1]) {
            return min;
        }
        for (int i = 1; i < n; ++i) {
            min = Math.min(min, nums[i]);
        }
        return min;
    }
}

解法二

思想:

首先,旋转后的数组实际可以划分为两个排序的子数组,而最小的元素刚好是这两 个子数组的分界线(第二个子数组的首位)。而且前面的子数组的元素都大于或等于后面的子数组的元素。

在排序数组中可以用二分查找实现O(logn)的查找。

所以我们可以通过二分查找的思路来寻找这个最小的元素。

算法:

利用指针 start,end 指向数组的首尾,如果 nums[start] < nums[end],说明数组是递增数组,直接返回 nums[start]。否则进行如下讨论。

计算中间指针 mid

  • 如果此时 nums[start]nums[end]nums[mid] 两两相等,此时无法采用二分方式,只能通过遍历区间 [start,end)获取最小值;
  • 如果此时 start,end 相邻,说明此时 end 指向的元素是最小值,返回 nums[end]
  • 如果此时 nums[mid] >= nums[start],说明 mid 位于左边的递增数组中,最小值在右边,因此,把 start 指向 mid,此时保持了 start 指向左边递增子数组;
  • 如果此时 nums[mid] <= nums[end],说明 mid 位于右边的递增数组中,最小值在左边,因此,把 end 指向 mid,此时保持了 end 指向右边递增子数组。

执行过程图示例:(阴影部分为第二个子数组)

(a) 把p1指向数组的第一个数字,p2指向数组的最后一个数字。中间数字5大于p1指向的数字(递增),所以中间的数字在第一个子数组中。下一步把p1指向中间的数字。

(b) p1和p2中间的数字1小于p2指向的数字,中间的数字在第二个子数组中。下一步把p2指向中间的数字(最小值在第二子数组首位,向左靠)。

(c) p1和p2指向两个相邻的数字,则p2指向的数组中的最小数字。

特殊情况:

在这两个数组中,第一个数字、最后一个数字和中间的数字都是1(相等),无法确定中间的数字1属于第一个递增子数组还是第二个。

public class Solution {

    public static int findMin(int[] nums){
        if(nums==null || nums.length==0) return -1;

        int start=0, end=nums.length-1;

        if(nums[start] < nums[end]) return nums[start]; //旋转了0个元素的情况

        int mid = 0;
        while(nums[start] >= nums[end]){//前面的子数组的元素都大于或等于后面的子数组的元素
            if(end-start==1){
                mid = end;
                break;
            }
            mid = (start + end)/2;

            if(nums[start] == nums[end] && nums[mid] == nums[start]){ //start、end、mid均相等,则只能顺序查找了
                return findMin(nums, start, end);
            }

            if(nums[mid]>=nums[start]) //在第一个子数组
                start = mid;
            else if(nums[mid]<=nums[end]) //在第二个子数组
                end = mid;
        }

        return nums[mid];
    }

    private static int findMin(int[] nums, int start, int end) {
        int min = Integer.MAX_VALUE;
        for(int i=start;i<end;i++)
            min = Math.min(min, nums[i]);
        return 0;
    }

    public static void main(String[] args) {
        int[] nums = {3,4,5,1,2,3};
        int[] nums1 = {1,0,1,1,1};
        int[] nums2 = {1,1,1,0,1};
        System.out.println(findMin(nums1));
    }
}

原文地址:https://www.cnblogs.com/lisen10/p/11065565.html

时间: 2024-11-10 12:58:31

剑指:旋转数组的最小数字的相关文章

【剑指offer】旋转数组的最小数字

题目描述: 把一个数组最开始的若干个元素搬到数组的末尾,称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1. 分析描述: 求一个数组中的最小值,最简单的办法就是逐个比较数组中各个元素的值,遍历完整个数组,即可得数组中最小元素.但这种方法存在的问题是时间复杂度为O(n). 利用题目中给出的条件:递增排序数组的旋转.利用递增排序的特点,可以用二分查找方法实现时间复杂度为O(logn)的查找.

【剑指Offer面试题】 九度OJ1386:旋转数组的最小数字

题目链接地址: http://ac.jobdu.com/problem.php?pid=1386 题目1386:旋转数组的最小数字 时间限制:1 秒内存限制:32 兆特殊判题:否提交:6914解决:1534 题目描述: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1. 输入: 输入可能包含多个测试样例,对于每个测试案例, 输入的第一行为

剑指OFFER之旋转数组的最小数字(九度OJ1386)

题目描述: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1. 输入: 输入可能包含多个测试样例,对于每个测试案例, 输入的第一行为一个整数n(1<= n<=1000000):代表旋转数组的元素个数. 输入的第二行包括n个整数,其中每个整数a的范围是(1<=a<=10000000). 输出: 对应每个测试案例, 输出旋转数组

剑指offer 面试题8:旋转数组的最小数字 题解

面试题8:旋转数组的最小数字 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个已从小到大排好序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1.(要求不能直接遍历数组来求解.) 提交网址: http://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba?tpId=13&tqId=11159 或 http:

剑指Offer:旋转数组的最小数字【11】

剑指Offer:旋转数组的最小数字[11] 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1. NOTE:给出的所有元素都大于0,若数组大小为0,请返回0. 解题分析 我们用两个坐标,Left,Right分别表示左右两个递增序列的下标,刚开始L为0,R为4: 当Arr[Mid]>Arr[Left],可以说明,Mid及左边构

【Java】 剑指offer(10) 旋转数组的最小数字

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1. 思路 数组在一定程度上是排序的,很容易分析出:可以采用二分法来寻找最小数字. 但是这里面有一些陷阱: 1.递增排序数组的本身是自己的旋转,则最小数字

剑指Offer 11. 旋转数组的最小数字

12345678910111213141516171819202122232425262728293031323334353637383940414243 public class { public int minNumberInRotateArray(int[] array) { int index1 = 0; int index2 = array.length - 1; int indexMid = 0; if (array.length == 0) { return 0; } while

剑指offer java -查找旋转数组的最小数字

/** * Created by wqc on 2017/7/18. * 查找旋转数组的最小数字 * 把一个数组最开始的若干个元素搬到数组的末尾,称为数组的旋转 * 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素 * 如:3,4,5,1,2 为1,2,3,4,5的一个旋转,最小值为1 */public class Problem8_findMinNumber { public Integer findMinNum(int[] array) { if(array == null) { r

《剑指offer》— JavaScript(6)旋转数组的最小数字

旋转数组的最小数字 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1. NOTE:给出的所有元素都大于0,若数组大小为0,请返回0. 实现代码 function minNumberInRotateArray(rotateArray) { var len=rotateArray.length; if(len== 0 || !r

剑指Offer面试题:7.旋转数组的最小数字

一.题目:旋转数组的最小数字 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1. 这道题最直观的解法并不难,从头到尾遍历数组一次,我们就能找出最小的元素.这种思路的时间复杂度显然是O(n).但是这个思路没有利用输入的旋转数组的特性,肯定达不到面试官的要求. 我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的