剑指offer第二版——面试题11(java)

本文介绍了一种高效算法,用于在旋转过的递增数组中找到最小元素。通过对比数组的起始、中间和结束位置元素,算法能快速定位最小值,即使在数组含有重复元素的情况下也能正确处理。

面试题11:旋转数组的最小数字

题目:

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素

例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。

 

方法:

对比取数组中的中间部分,start,mid和end,

循环(start<end)

    ①如果start和end只相差1(比较到了最后)

               a. 如果end == A.length-1-loc,则为递增数列

               b. 如果a不成立,则比较A[start]和A[end],更小的为最小值

    ② 如果A[start] == A[end],缩短数组 start++  end-- 且loc++(用于定位数组末尾,判断是否为递增数列)

    ③ 如果A[start]!= A[end],比较A[start]和A[mid],若A[start]<A[mid],则左边为递增数组,将start赋值为mid

    ④ 如果一直比对到start=end,则返回loc位置

 

案例:

eg: 5 6 7 8 1 2 3 4 (正常旋转数组)

①start=0,end=7,mid=3  A[0]<A[7]  → start=3

②start=3, end=7, mid=5  A[3]>A[7] → end=5

③start=3, end=5, mid=4 A[3] >A[4] → end=4

④此时start+1=end 进入判断,end!== A.length-1-loc(loc此时为0),A[start]和A[end]中更小的为1

 

eg:1 1 1 1 0 1 1 1  (两端有重复值时,无法通过两边的大小来判断递增)

① start=0,end=7,mid=4 两端相等→ start=1, end=6,loc=1

② start=1,end=6,mid=4 两端相等→ start=2,end=5,loc=2

③ start=2,end=5,mid=4 两端相等→ start=3,end=4,loc=3

④ start=3,end=4,mid=4 此时start+1=end 进入判断,end != A.length-1-loc(loc此时为0),返回更小值,即0 

 

eg: 0 1 2 3 4 5 6 (递增数组时,最小值为A[0])

① start=0,end=6,mid=3 A[0]<A[6] →start=3

② start=3, end=6,mid=4  A[3]<A[4] →start=4

③ start=4,end=6,mid=5 A[4]<A[5] → start=5

④ start=5,end=6,此时start+1=end 进入判断,end == A.length-1-loc(loc此时为0),返回loc位置,即A[0] 

public class Q11 {
	public static void main(String[] args) {
		int[] A = new int[] {1,2};
		System.out.println(findNum(A));
	}
	
	public static int findNum(int[] A) {
		int left = 0;
		int right = A.length-1;
		int mid = 0;
		int loc = 0;
		while(left<right) {
			mid = (left+right)/2;
			System.out.printf("left:%d,right:%d,mid:%d\n", left,right,mid);
			if(left+1==right) {
				// 防止递增数列
				if(right == A.length-1-loc) {
					return A[loc];
				}
				if(A[left]<A[right]) {
					return A[left];
				}else {
					return A[right];
				}
			}
			
			// 两边相等 则缩小范围
			if(A[left] == A[right]) {
				left++;
				right--;
				loc = left;
			}else {
				// 两边不相等 再和中间的相比
				if(A[left]<A[mid]) {
					System.out.printf("A[%d]:%d < A[%d]:%d\n",left,A[left],mid,A[mid]);
					left = mid;
				}else if(A[left]>A[mid]) {
					System.out.printf("A[%d]:%d > A[%d]:%d\n",left,A[left],mid,A[mid]);
					right = mid;
				}
			}
		}
		return A[loc];
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值