题目:https://www.nowcoder.com/ta/coding-interviews
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序 的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思考:
利用旋转数组的特性来设计查找最小值的方法。
原数组是非递减排序 的,旋转数组可划分为两个非递减子数组,并且前面子数组的元素都>=后面子数组的元素,最小元素恰好是两个数组的分界线;
暴力的o(n)查找
1 2 3 4 5 6 7 8 9 10 class Solution1 : def minNumberInRotateArray (self, rotateArray) : min = rotateArray[0 ] if len(rotateArray)==0 : return 0 else : for i in range(1 ,len(rotateArray)): if rotateArray[i] < min: min = rotateArray[i] return min
1 2 3 rotateArray = [4 , 5 , 6 , 1 , 2 , 3 ] method = Solution1() method.minNumberInRotateArray(rotateArray)
1
根据旋转数组的特性设计二分查找:
1.设置中间点,标记旋转数组首元素和尾元素,中间点将数组分成两半;
2.如果中间点大于等于首元素,说明最小数字在数组后一半,如果中间点小于等于尾元素,说明最小数字在数组前一半;
3.依次改变首、尾元素的位置,当尾元素和首元素挨着的时候,这时候尾元素 就是所找的最小值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution2 : def minNumberInRotateArray (self, rotateArray) : left = 0 right = len(rotateArray)-1 if len(rotateArray)==0 : return 0 else : while (right - left) > 1 : mid = (left + right)//2 if rotateArray[mid] >= rotateArray[left]: left = mid elif rotateArray[mid] <= rotateArray[right]: right = mid return rotateArray[right]
1 2 3 rotateArray = [4 , 5 , 6 , 1 , 2 , 3 ] method = Solution2() method.minNumberInRotateArray(rotateArray)
1
特殊的是,当首元素等于尾元素等于中间值时,以上比较规则失效,只能对数组进行顺序查找,增加如下判断:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution3 : def minNumberInRotateArray (self, rotateArray) : left = 0 right = len(rotateArray)-1 if len(rotateArray)==0 : return 0 else : while (right - left) > 1 : mid = (left + right)//2 if rotateArray[mid] == rotateArray[left] and rotateArray[mid] == rotateArray[right]: min = rotateArray[left] for i in range(left,right): if rotateArray[i] < min: min = rotateArray[i] return min elif rotateArray[mid] >= rotateArray[left]: left = mid elif rotateArray[mid] <= rotateArray[right]: right = mid return rotateArray[right]
1 2 3 4 rotateArray = [ 0 , 1 , 1 ] method = Solution3() method.minNumberInRotateArray(rotateArray)
1
剑指offer书中还考虑到旋转数组旋转了0个元素的情况,也就是排序数组本身:第一个元素(左)就是最小的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution : def minNumberInRotateArray (self, rotateArray) : left = 0 right = len(rotateArray)-1 if len(rotateArray)==0 : return 0 elif rotateArray[left] < rotateArray[right]: return rotateArray[left] else : while (right - left) > 1 : mid = (left + right)//2 if rotateArray[mid] == rotateArray[left] and rotateArray[mid] == rotateArray[right]: min = rotateArray[left] for i in range(left,right): if rotateArray[i] < min: min = rotateArray[i] return min elif rotateArray[mid] >= rotateArray[left]: left = mid elif rotateArray[mid] <= rotateArray[right]: right = mid return rotateArray[right]
1 2 3 4 5 6 rotateArray = [ 0 , 1 , 1 , 1 ] method = Solution() method.minNumberInRotateArray(rotateArray)
0
这里补充另一位博主的写法Solution4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution4 : def minNumberInRotateArray (self, rotateArray) : p1, p2 = 0 , len(rotateArray) - 1 mid = p1 while rotateArray[p1] >= rotateArray[p2]: if p2 - p1 == 1 : mid = p2 break mid = (p1 + p2) // 2 if rotateArray[mid] == rotateArray[p1] and rotateArray[mid] == rotateArray[p2]: return self.minInOrder(rotateArray, p1, p2) if rotateArray[mid] >= rotateArray[p1]: p1 = mid elif rotateArray[mid] <= rotateArray[p2]: p2 = mid return rotateArray[mid] def minInOrder (self, nums, index1, index2) : n1 = nums[index1] for i in range(index1 + 1 , index2): if n1 > nums[i]: return nums[i] return n1
1 2 3 4 5 6 rotateArray = [4 , 5 , 6 , 1 , 2 , 3 ] method = Solution4() method.minNumberInRotateArray(rotateArray)
1
参考:
https://blog.csdn.net/Datawhale/article/details/82143776
https://blog.csdn.net/fuxuemingzhu/article/details/79501202
最后更新时间:2019-08-21 21:29:47