剑指offer系列(7)——旋转数组的最小数字

本文介绍了一种在旋转数组中查找最小元素的有效算法。通过利用数组的特性,采用类似于二分查找的方法,即使数组含有重复元素也能正确找到最小值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目要求如下:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。

这个题的突破口是要发现一个这种排序数组的一个特点:即旋转将数组分成了两个部分的小数组,而后面这个小数组的每个值小于前面的小数组(这里不考虑特殊情况,默认为排序好的递增数组,且其中元素不重复,重复的在后面讨论)

当处于这种情况时,我们只需利用上面的这个特点,即最小得值一定在第二个数组中且一定小于第一个数组中的最小值(第一个数组中最小值为第一个值,eg:[3,4,5,1,2]中的3),这个时候我们可以采用类似二分查找的方法。令一个first下标遍历指针,在令一个final下标遍历指针,这两个指针分别指向第一个元素和最后一个元素,根据其中间值的大小不断缩小范围直至找到。伪代码如下:

If(middle > indexfirst)
                first = middleelse ifmiddle < indexfirst)
                final = middle;
        else
                特殊情况

下面我们分析特殊情况,当这个数组中有重复值时,并且导致了middle和indexfirst相等。
这里也要分为两种情况:
1) 若first和final之间是全为某一个数的特殊情况,这是,我们只能进行循环遍历。
2) 若first值与中间值相同,但与final值不同,如[5,5,5,1,1],此时我们的算法仍旧可以处理这种情况。所以,这种情况并不用考虑。

综上,我们可以写出代码:

package com.offer;

public class MinNumberInRotatedArray {
    /*
     * 旋转数组找最小值
     * 
     * 注意!只有低位高位中间位三者完全一样时才采用遍历寻找  ,防止 5,5,5,1,2 ,所以要把特殊情况放在前面
     */
    public static void main(String[] args) {
        int[] a = new int[]{4,5,1,2,3};
        System.out.println(findMinNumber(a));

    }

    public static int findMinNumber(int[] array){
        if (array == null || array.length <= 0) {

            throw new RuntimeException("数组为空或长度小于等于零");
        }
        int low = 0;                    //低位遍历指针
        int high = array.length - 1;    //高位遍历指针
        if (array.length == 1) {        //只有一个元素
            return array[0];    
        }
        int result = 0;                 //最小值
        while(Math.abs(high - low) != 1){
            if (array[low] == array[high] && array[high] == array[(low + high) >> 1]) {
                //中间值与低位元素与高位元素相等,无法判断,必须遍历查询
                for (int i = 0; i < array.length; i++) {
                    result = result > array[i] ? array[i] : result;
                }
                break;      //跳出while循环 否则将无限执行下去 !

            }else if(array[(low + high) >> 1] < array[low]){
                //以最小值为界,中间值在后面
                high = (low + high) >> 1;

            }else{
                //以最小值为界 ,中间值在前面
                low = (low + high) >> 1;

            }
        }

        result = array[high];





        return result;


    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值