《剑指offer》11.旋转数组的最小数字

旋转数组的最小数字

LeetCode:剑指offer 11.旋转数组的最小数字

题目描述:

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

解题思路

如果遇到从排序的数组中查找数字需要尝试二分查找法

我们利用两个指针分别指向数组的第一个元素和最后一个元素,我们可以先找到数组中间的元素,如果该中间元素大于或等于第一个元素,则位于前面的非递减子数组,此时我们就可以把第一个指针指向该中间元素,这样就可以缩小寻找的范围,移动以后,第一个指针依然指向前面的非递减数组;否则属于后面的非递减子数组,此时我们就可以把第二个指针指向该中间元素,移动以后,第二个指针依然指向后面的非递减数组。然后循环下去,最终第一个指针将指向前面子数组的最后一个元素,而第二个指针将会指向后面子数组的第一个元素,而第二个指针指向的刚好是最小的元素。循环结束。

特例:

  1. 如果数组整体就是一个排序的数组可以直接返回
  2. 当出现多个重复的数字时不得不使用顺序查找的方式

参考代码:

class Solution {
    public int minArray(int[] numbers) {
        int len =numbers.length;
        //长度为0直接返回
        if(len==0){
            return 0;
        }
        int left=0;
        int right=len-1;
        //刚开始就是排序的数组,直接返回第一个即可
        if(numbers[left]<numbers[right]){
            return numbers[left];
        }
        while(left<right){
            //int mid = i+(j-i)/2;
            int mid = (left+right)/2;
            //最小数位于前面
            if(numbers[mid]<numbers[right]){
                right=mid;
            }else if(numbers[mid]>numbers[right]){
                //最小数位于后面,
                //且临界条件时需要+1,用来终止循环
                left=mid+1;
            }else{
            //有相同值时需要跳过
                right--;
            }
                
        }
        return numbers[left];
    }
}

补充

如果面试题是要求在排序的数组(或者部分排序的数组)中查找一个数字或者统计某个数字出现的次数, 那么我们都可以尝试 二分查找算法。

强烈建议在准备面试的时候,一定要对各种排序算法的特点烂熟于胸,能够从额外空间消耗、平均时间复杂度和最差时间复杂度等方面去比较他们的优缺点。(特别关注手写快排)

快排算法思想如下:
先在数组中选择一个数字,接下来吧数组中的数字分为两部分,比选择的数字小的数字移到数组的左边,比选择的的数字大的数字移到数组的右边 (善用指针的想法)。然后左右两侧分别递归得到最后结果。

import java.util.Random;

/**
 * 快速排序
 */
public class QuickSort {

    /**
     * 交换数组中的两个值
     * @param array
     * @param a
     * @param b
     */
    public static void swap (int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }


    /**
     * 分区函数
     * 按随机出的基准值分区,将比基准值小放在基准值左边,大的放在基准值右边
     * @param data
     * @param length
     * @param start
     * @param end
     * @return
     * @throws Exception
     */
    public static int partition(int data[], int length, int start, int end) throws Exception {

        Random random = new Random();

        if (data == null || length <=0 || start <0 || end >= length) {
            throw new Exception("Invalid Parameters");
        }

        // 尽量避免极端情况,每次都是以最后一个数字作为基准值,在start和end之间随机出一个数
        int index = start + random.nextInt(end - start + 1);

        // 将比较的值放在数组的最后
        swap(data, index, end);

        // 定义一个指针,指向所有换序之后所有比基准值都小的数据的最右边,最后最指向基准值应该在位置
        int small = start - 1;

        for (int i = start; i < end; i++) {
            if (data[i] < data[end]) {
                small++;
                // 避免原来就是有序数列的无用交换
                if (small != i) {
                    swap(data, small, i);
                }
            }
        }
        // 把基准值放在中间
        small++;
        swap(data, small, end);
        return small;
    }

    /**
     * 利用分区函数实现快速排序
     * 递归
     * @param data
     * @param length
     * @param start
     * @param end
     * @throws Exception
     */
    public static void quickSort(int[] data, int length, int start, int end) throws Exception {
        // 当只剩一个数的时候就不用递归了
        if (start == end) {
            return;
        }
        int index = partition(data, length, start, end);
        // 防止异常
        if (index > start) {
            quickSort(data, length, start, index - 1);
        }
        if (index < end) {
            quickSort(data, length, index + 1, end);
        }

    }
  }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值