剑指offe面试题8 旋转数组的最小数字 (java实现)

解题思路:

针对旋转数组的特点,即旋转后,数组的前半部分是有序的,后半部分是有序的。

1.先考虑一般情况:可以参考二分查找的思想,在数组中设置两个指针,一个指向数组的起始位置,一个指向数组的结束位置。随后依据这两个位置求出数组的中间位置mid。如果mid指向元素大于等于start指向元素,则证明mid肯定在数组的前半部分,而旋转数组的最小值在mid的后面,因此可以缩小查找范围,令start = mid;如果mid指向元素小于start指向元素并且小于等于end指向指向元素,则证明mid肯定在数组的后半部分,而最小值在mid之前或者就是mid指向的元素,因此可以缩小查找范围,令end = mid。直到end - start == 1为止,此时end指向的元素即为旋转数组的最小值。

2.本题还需考虑两种特殊情况:(1)若是这样的旋转数组,即先赚前面的0个元素到后面,即数组还是一开始的排序数组,那么数组中的第一个数字即为最小的元素;(2)当start和end和mid指向元素相同时,此时无法判断mid所指元素属于前半部分还是后半部分,因此只能进行顺序查找。

public class Solution {
    /**
	 * 利用二分查找完成寻找最小的元素
	 * 
	 * @param array
	 * @return
	 */
	public int minNumberInRotateArray(int[] array) {
		// 初始化数组的启示索引和结束索引
		int firstIndex = 0;
		int lastIndex = array.length - 1;
		int midIndex = firstIndex;
		// 旋转数组中一般情况下第一个元素是大于等于最后一个元素的
		// 而如果数组中第一个数字小于最后一个数字,表明该数组本身是排序的,即相当于旋转了前0个元素到后面
		while (array[firstIndex] >= array[lastIndex]) {

			if (lastIndex - firstIndex == 1) {
				midIndex = lastIndex;
				break;
			}
			// 求出中间位置的索引
			midIndex = (firstIndex + lastIndex) / 2;

			// 如果第一个指针和第二个指针和第三个指针指向的三个数字相等,则只能顺序查找
			if (array[firstIndex] == array[lastIndex] 
				&& array[midIndex] == array[firstIndex]
				&& array[midIndex] == array[lastIndex]) {
				return minInOrder(array, firstIndex, lastIndex);

			}

			if (array[midIndex] >= array[firstIndex]) {
				// 此时说明中间元素处于左边这个子数组中,而最小的元素位于中间元素的后面
				// 将第一个指针指向该中间元素,该指针仍然位于前面这个递增子数组中
				firstIndex = midIndex;
			} else if (array[midIndex] <= array[lastIndex]) {
				// 如果中间元素位于右边的递增子数组,则它所指向元素应该小于等于第二个指针指向的元素
				// 此时最小的元素在该中间元素的前面,移动之后的第二个指针仍然在第二个递增子数组中
				lastIndex = midIndex;
			}

		}
		// 此时第二个指针指向的元素即为旋转数组中最小的元素
		return array[lastIndex];

	}

	private int minInOrder(int[] array, int firstIndex, int lastIndex) {
		int minNum = array[firstIndex];
		for (int i = firstIndex + 1; i <= lastIndex; i++) {
			if (array[i] < minNum) {
				minNum = array[i];
			}
		}
		return minNum;
	}
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值