剑指OFFER笔记_11_旋转数组的最小数字_JAVA实现

题目:旋转数组的最小数字

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

解题思路

  • 可以用从头到尾遍历一次找到最小值,时间复杂度为O(n)。
  • 旋转数组可以看作是两个排序的数组,其中第一个数组的最小值大于后一个数组的最大值。而最小数字就是后一个数组的第一个元素。所以我们只要找到两个数组的分界元素,就可以找到最小数字。
  • 如果利用二分法查找,那么时间复杂度将是O(logN)。
  • 用high和low分别存储当前范围的和数组下标的上下限。mid=(low+high)/2指向中间的元素。
  • 如果num[mid]<num[low],说明分界在mid的左边,也就是下次检索的范围是low到mid,所以high=mid。如果num[mid]>num[low],说明分界在mid的右边,也就是下次检索的范围是mid到high,所以low=mid。
  • 直到low和high为相邻的元素,说明low指向前一个数组的最大元素,high指向后一个数组的最小元素。
  • 我们还需要考虑一些特殊情况:数组中存在一些相等的元素,如果low、mid、high指向的元素全部相同,我们就无法判断下一次检索的范围应该是什么,此时只能采取从头到尾该范围的遍历算法了。
  • 还有一种特殊情况,数组旋转了0次,此时两个缩小范围的判断条件的都不符合,第一个元素就是我们要找的值。
  • 综合以上的思路和特殊情况处理,可以写出如下代码:

代码

函数主体部分代码

package q11;

public class Solution {
	public int minArray(int[] numbers) {
		//异常处理
		if(numbers == null || numbers.length == 0)
		{
			return -1;
		}
		
		//low用来控制范围的下限
		//high用来控制范围的上限
		//mid为中值
		int low = 0;
		int high = numbers.length-1;
		int mid = (low + high) / 2;
		
		//旋转次数为0的特殊情况,第一个元素即为最小元素
		if(numbers[low] < numbers[high])
		{
			return numbers[0];
		}
		
		//此时旋转次数一定不为0
		//结束条件是两个下标相邻。
		while(low < high - 1)
		{
			mid = (low + high) / 2;
			
			//如果出现low、high、mid相等的情况无法继续判断,只能顺序检测
			if(numbers[low] == numbers[high] && numbers[low] == numbers[mid])
			{
				return MinInOrder(numbers, low, high);
			}
			
			//如果mid的数小于low的数,则说明最小的数字在low和mid之间,所以把mid赋值给high
			if(numbers[mid] < numbers[low])
			{
				high = mid;
				continue;
			}
			//如果mid的数大于high的数,则说明最小的数字在mid和high之间,所以把mid赋值给low
			if(numbers[mid] > numbers[high])
			{
				low = mid;
				continue;
			}
		}
		//当low和high相邻时,右边的high就是最小数。
		return numbers[high];
    }
	
	/**
	 * 用顺序遍历的方法去寻找最小数
	 * @param numbers
	 * @param low
	 * @param high
	 * @return
	 */
	public int MinInOrder(int[] numbers, int low, int high)
	{
		if(numbers == null || numbers.length == 0)
		{
			return -1;
		}
		int min = numbers[low];
		for (int i = low; i <= high; i++) 
		{
			if(numbers[i] < min)
			{
				min = numbers[i];
			}
		}
		return min;
	}
}

测试部分代码

package q11;

public class TestApp {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] nums1 = null;
		int[] nums2 = {};
		int[] nums3 = {2,2,0,2,2,2,2};
		int[] nums4 = {1,2,3,4,5,6,7};
		int[] nums5 = {3,4,5,6,1,2};
		
		Solution s = new Solution();
		System.out.println("The min value in nums1[] is:" + s.minArray(nums1));
		System.out.println("The min value in nums2[] is:" + s.minArray(nums2));
		System.out.println("The min value in nums3[] is:" + s.minArray(nums3));
		System.out.println("The min value in nums4[] is:" + s.minArray(nums4));
		System.out.println("The min value in nums5[] is:" + s.minArray(nums5));
	}
}

运行结果截图

在这里插入图片描述

LeetCode运行截图

在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值