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

一、题目
————————————————
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。
————————————————
二、思路
————————————————
  数组在一定程度上是排序的,很容易分析出:可以采用二分法来寻找最小数字。
  但是这里面有一些陷阱:
  1.递增排序数组的本身是自己的旋转,则最小数字是第一个数字
  2.中间数字与首尾数字大小相等,如{1,0,1,1,1,1}和{1,1,1,1,0,1},无法采用二分法,只能顺序查找。
————————————————
三、解决问题
————————————————
测试用例
  1.功能测试(正常旋转数组,中间有或者无重复数字)
  2.边界值测试(升序数组,1个数字的数组)
  3.特殊输入测试(null,空数组)
————————————————

package swordoffer;

/**
 * @author LQ
 * @version 1.0
 * @date 2020-03-14 10:12
 */

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

 */

public class Solution09 {

    public static void main(String[] args) {
        System.out.println("==============================");
        Solution09 sword = new Solution09();
        sword.test1();
        System.out.println("==============================");
        sword.test2();
        System.out.println("==============================");
        sword.test3();
        System.out.println("==============================");
        sword.test4();
        System.out.println("==============================");
        sword.test5();
        System.out.println("==============================");
        sword.test6();
        System.out.println("==============================");
        sword.test7();
        System.out.println("==============================");
    }

    /**
     * 数组在一定程度上是排序的,很容易分析出:可以采用二分法来寻找最小数字。
       但是这里面有一些陷阱:
       1.递增排序数组的本身是自己的旋转,则最小数字是第一个数字
       2.中间数字与首尾数字大小相等,如{1,0,1,1,1,1}和{1,1,1,1,0,1}
           无法采用二分法,只能顺序查找。
     * @param array
     * @return
     */
    public int minNumberInRotateArray(int [] array) {
        //空数组或者null时返回0
        if (null == array || array.length <= 0) {
            return 0;
        }
        int low = 0;
        int high = array.length - 1;
        //正常情况
        while (low < high) {
            int mid = low + (high - low) / 2;
            if (array[mid] > array[high]) {
                low = mid + 1;
            } else if (array[mid] == array[high]) {
                high = high - 1;
            } else {
                high = mid;
            }
        }
        return array[low];
    }
    // =======测试代码======
    public void test1() {
        int[] array = null;
        System.out.println("test1:" + minNumberInRotateArray(array));
    }

    public void test2() {
        int[] array = {};
        System.out.println("test2:" + minNumberInRotateArray(array));
    }

    public void test3() {
        int[] array = { 1 };
        System.out.println("test3:" + minNumberInRotateArray(array));
    }

    public void test4() {
        int[] array = { 1, 2, 3, 4, 5, 6 };
        System.out.println("test4:" + minNumberInRotateArray(array));
    }

    public void test5() {
        int[] array = { 2, 2, 2, 2, 1, 2 };
        System.out.println("test5:" + minNumberInRotateArray(array));
    }

    public void test6() {
        int[] array = { 2, 1, 2, 2, 2, 2 };
        System.out.println("test6:" + minNumberInRotateArray(array));
    }

    public void test7() {
        int[] array = { 6, 6, 8, 9, 10, 1, 2, 2, 3, 3, 4, 5, 6 };
        System.out.println("test7:" + minNumberInRotateArray(array));
    }
}

————————————————
 注意这段代码的一些细节:
  1.使用low=mid+1,而不是low=mid,最终会使得low=high(即最小值位置)而跳出循环;
  2.使用high=mid,而不是high=mid-1,因为有可能mid就是最小值点,不能减1;
  3.升序数组的情况可以直接在循环中一起搞定,不用单独列出来判断(自己的代码还可以改进)
  小瑕疵:
  1.该程序在array[mid] = array[high]时直接顺序查找。但其实这还有可能可以用二分法的,除非还满足array[mid] = array[low],才只能使用顺序查找。所以可以先排除掉必须顺序查找的情况(类似自己上面的程序,提前判断掉),之后就可以直接删除else if(array[mid] == array[high]){high = high - 1;这两行了。
  2.缺少null的判断。
————————————————
图片说明
————————————————
努力也是需要学习的,别再让你的努力,只感动了自己!愿你的每一次努力,都能为自己和别人创造价值。

Java基础 文章被收录于专栏

建立本人的Java基础技术栈积累库

全部评论

相关推荐

评论
点赞
收藏
分享
牛客网
牛客企业服务