leetcode刷题
153. 寻找旋转排序数组中的最小值
题目
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
分析
nums是一个经过旋转后的有序数组。根据二分法将矩阵分为[left:mid]和[mid:right]两部分,首先判断循环结束条件。即nums[mid]比两边的数都小nums[mid]<=nums[mid-1]和nums[mid]<=nums[mid+1]
,注:因为是java,所以要写成nums[mid]<=nums[(mid+nums.length-1)%nums.length] && nums[mid]<=nums[(mid+1)%nums.length],其中+length以及%length是为了防止首和尾,python就不用考虑这个问题了;而=号是为了防止只有nums.length==1。
接下来只对[left:mid]进行分析,判断什么情况下最小值会留在[left:mid]区域。如图一所示,当[left:mid]呈现下图趋势时nums[left]>nums[mid]
,最小值一定存留在本区域,不用考虑[mid:right]。
图一
而[left:mid]呈图二中的趋势时候,需要考虑[mid:right]区域,其具有三种可能,但是只有呈现①中的趋势时nums[right]>nums[mid] and nums[right]>nums[mid] 合并为nums[right]>nums[left]
,最小值才会留在[left:mid]区域中。
若留在[left:mid]中,即将right = mid - 1
保留该区域,撇弃[mid:right]。反之亦然left = mid + 1
代码
public int findMin(int[] nums) {
int left = 0;
int right = nums.length-1;
int mid;
while(left<=right){
mid = (left+right)/2;
if (nums[mid]<=nums[(mid+nums.length-1)%nums.length] && nums[mid]<=nums[(mid+1)%nums.length]){
return nums[mid];
}
else if (nums[left]>nums[mid] || nums[right]>nums[left]){
right = mid - 1;
}
else {
left = mid + 1;
}
}
return -1;
}
结果
时间超过100.00%
内存超过70.75%