剑指offer第10题旋转数组的最小数字

Posted rushup0930

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer第10题旋转数组的最小数字相关的知识,希望对你有一定的参考价值。

【题目】

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

输入一个升序的数组的一个旋转,输出旋转数组的最小元素。

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

数组可能包含重复项。

注意:数组内所含元素非负,若数组大小为0,请返回-1。

样例
输入:nums=[2,2,2,0,1]

输出:0

【思路】

这个题目最直观的解法并不难,从头到尾遍历数组一次,就可以找出最小的元素。这种思路的时间复杂度显然是O(n)。但是并没有利用旋转数组的特性。应该不是最佳的解法。

我们注意到旋转之后得到的两个数组都是有序的,而且前面的子数组的元素要大于或者等于后面子数组的元素。我们还注意到最小的元素刚好是这两个子数组的分界线,在排序的数组中我们可以使用二分法实现O(logn)的查找。

另外我们注意到使用O(n)的时间复杂度无法求解时,就应该想到是否能用O(logn)的时间复杂度来求解。

【通常情况】和二分查找一样,使用两根指针分别指向数组的第一个元素和最后一个元素,根据题目中的旋转规则,第一个元素应该是大于或者等于最后一个的。接着我们可以找到数组的中间元素,如果该中间元素位于前面递增的子数组,那么他应该大于或者等于第一个指针指向的元素。此时分界点元素(最小值)应该在后一个子数组。此时我们可以将头指针指向该中间元素,缩小了查找范围。

同样的道理,如果中间元素位于后面的递增子数组,那么他应该小于或者等于第二个指针指向的元素,此时分界点元素(最小值)应该在前一个子数组,此时我们可以将尾指针指向该中间元素,缩小了查找范围。

按着上面的思路:第一个指针总是指向前面递增数组的元素,第二个指针总是指向后面递增数组的元素也就是说他们最后会指向两个相邻的元素,而第二个指针刚好指向的是最小的元素。这也是循环结束的条件。

【特例】

如果将排序数组的前面0个元素搬到最后面,即排序数组的本身,这仍然是一个旋转,我们上述代码思路是支持这种情况的。即数组中的第一个元素即为最小的数字。特例:数组{1,0,1,1,1}和数组{1,1,1,0,1} 可以看成是递增排序数组{0,1,1,1,1}的旋转。这两种情况使用上述二分思路,第一个指针和第二个指针以及中间值都相等,则我们没办法判断中间数字是位于前半部分的子数组中还是后半部分的子数组中,也就无法通过移动两个指针来缩小查找的范围。此时我们不得不采用顺序查找的方法进行查找。

 

【代码】

以上是关于剑指offer第10题旋转数组的最小数字的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer面试题 11. 旋转数组的最小数字

[剑指offer]面试题8:旋转数组的最小数字

剑指Offer之旋转数组中的最小数字(题8)

旋转数组的最小数字 - 剑指offer 面试题8

剑指Offer面试题:6.旋转数组中的最小数字

Java 剑指offer(10) 旋转数组的最小数字