数组2:旋转数组的最小数字

题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}{1,2,3,4,5}的一个旋转,该数组的最小值为1NOTE:给出的所有元素都大于0,若数组大小为0,请返回0

思路:何为旋转数组?已知一个排序递增的数组,如果将最前面的几个数字整体拿到了数组的最后面得到的就是旋转数组。

12345678—>78123456; 12345678—>3456781;1234567à5671234旋转数组有一个特性:它可以看做是两个有序的数组,最小值必定是在数组中间的某个位置,并且一定是第二个数组的第一个元素。

这是一个最小值的查找问题,可以通过排序得到,最小时间复杂度为O(nlogn)-快排,堆排;由于是查找特殊值(最大最小的值),可以顺序查找记录最小值,时间复杂度为O(n).

也可以使用二分查找的方式,时间复杂度为O(logn);对于数组array[left~right],int middle=(left+right)/2,先找出中间元素array[middle],然后与当前数组的第一个元素进行比较,如果array[middle]>array[left],那么说明array[middle]在第一个数组中,那么要查找的最小值一定在array[middle]的右边,于是调整数组范围为left=middle;right=right;(注意:left不能等于middle+1,因为可能middle后面部分恰好是顺序的,这样就不满足循环条件了,例如3,4,5,1,2,如果middle指向middle+11,那么1,2是排序的,属于特殊逻辑,不能通过这里的循环解决问题)再次找中间值,并与当前数组的第一个元素比较,如果array[middle]< array[left],说明array[middle]在第二个数组中,那么最小元素就是这个数或者在这个数的左边,于是调整范围为i=i;j= array[middle];如此循环,最终必然是剩下2个元素,即right-left=1时停止,并且比较array[left]array[right],其较小的值就是最小值,如果从某一个步骤开始array[middle]=array[left],那么无法判断最小值在左边还是右边,例如12333334à33333412à41233333,此时只能对当前范围的数组进行遍历查找来找到最小值。此题中也可以使用二分法,二分法只是一种思想,在不同问题中可以有不同的变化应用,例如传统二分法查找指定值是在整个数组有序的基础上进行的,它将数组分为leftrightmiddle,将targetmiddle比较来确定下一次的查找区间;而本题中是将数组分为left,right,middle,没有target,将middleleft比较来决定笑一次查找的区间,如果middle<left,在左侧(包含当前元素),如果middle>left,在右侧(包含本元素),如果middle=left,则只能顺序查找最小值。本题可以使用递归也可以使用循环来解决。

本题特殊情况:

1.输入为null或者length=0

2.一开始整个数组循序排列(即旋转了0个元素),需要作为特殊输入检验

3.从某个阶段开始array[middle]==array[left],需要顺序查找

import java.util.ArrayList;
//找出旋转数组中的最小值
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        //特殊输入:数组为null或者长度为0是不同的概念
        if(array==null||array.length==0) return 0;
        //特殊输入:不是旋转数组
        if(array[0]<array[array.length-1]) return array[0];
        //定义left,right指针使用二分法解决问题
        int left=0;
        int right=array.length-1;
        int middle=0;
        while(right-left>1){
            middle=(left+right)/2;
            if(array[middle]>array[left]){
                //最小值在middle的右侧
                left=middle;
            }else if(array[middle]<array[left]){
                //最小值在middle的左侧或者本身
                right=middle;
            }else{
                //此时需要对left-right进行遍历查找最小值
                return this.findMin(array,left,right);
            }
        }
        //此时只剩下两个元素,right-left=1
        if(array[left]<array[right]) return array[left];
        else{
            return array[right];
        }
    }
    //找出数组left-right范围内的最小值
    public int findMin(int [] array,int left,int right){
        int min=array[left];
        while(left<=right){
            if(array[left]<min){
                min=array[left];
            }
            left++;
        }
        return min;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值