略
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
用顺序查找就可以实现,但面对大量的数据时,可以用算法来优化查找。
分析
常规情况
对于一个旋转数组,第一个元素是比最后一个元素大的(大多数情况下,特殊情况下文中再说);那么对于这样的数组要实现查找,自然想到了二分查找,但是二分之后,如何选择最小值在哪个区域呢?可以举个例子,例如:有旋转数组array,它的元素是{5,6,7,8,9,1,2,3,4},它的头是array[0]=5,它的尾是array[8]=4,中间是array[4]=9,然后旋转数组的头一定是大于尾部的(排除特殊情况),然而中间的9大于5(比头还大),所以最小值在中间的右边,把头的指针移动到中间,在{9,1,2,3,4}中去找最小值,依次类推,头为9,尾为4,中为2,中小于尾(比尾还小),所以最小值在中间的左边,把尾的指针移动到中间,最后{9,1,2}中找最小值,头为9,尾为2,中为1,1小于2(比尾还小),尾部指针移动到中间,{9,1}中找最小,由于他们相距为1,则循环结束,输出尾指针,就是最小值了。
所以程序应该这么写:用头、尾指针来划定范围,中指针来判断如何移动头尾指针,如果中大于或等于头,则头指针移到中,如果中小于或等于尾,则尾指针移动到中,概括来就是:头大于尾,中间取数,与头比大,与尾比小,大头移头,小尾移尾,距离为1,尾部最小。
特殊情况
有时候会出现,旋转了0个元素的情况:就是没有旋转如{1,2,3,4,5,6},再用二分就不可以了,因为上文一直是在由尾元素来得到最小值,然而这次最小元素在第一个,不能是尾元素,所以说上文的程序是有前提条件的,那就是头比尾大,当头比尾小的时候就说明没有旋转,直接输出第一个元素就好了。
还有一种情况:那就是当出现头,尾,中三个元素相等的时候,例如{1,0,1,1,1}或者{1,1,1,0,1},说明上述程序并不完整,这时候就需要判断,当三元素相等时,就采用其他的查找方式,例如顺序查找。
代码实现
代码如下:
1 | import java.util.ArrayList; |
总结
- 虽然顺序查找可以做到,但是还要思考是否有更好的方法,如二分法。
- 要考虑到旋转数组的特例,如{1,2,3,4,5,6}和{1,1,1,0,1}。
- 后面的学习中要要求把二分查找学到信手拈来的程度。