【LeetCode & 剑指offer刷题】查找与排序题7:11旋转数组的最小数字(153. Find Minimum in Rotated Sorted Array)(系列)
【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)
153. Find Minimum in Rotated Sorted Array
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).
Find the minimum element.
You may assume no duplicate exists in the array.
Example 1:
Input: [3,4,5,1,2]
Output: 1
Example 2:
Input: [4,5,6,7,0,1,2]
Output: 0
/*
从头到尾遍历一遍为O(n)
*/
/*
问题:找旋转有序(增序)数组(不含重复数)中的最小数
分析:
旋转后,会形成两个有序左右子数组,且左子数组的数一定比右子数组的数大
如[3,4,5,1,2]
方法:二分查找
O(logn), O(1)
*/
class Solution
{
public:
int findMin(vector<int> &nums)
{
int left = 0, right = nums.size() - 1;
if (nums[left] > nums[right]) //若有旋转
{
while (left < right - 1)
{
int mid = (left + right) / 2;
if (nums[left] < nums[mid]) //若中间的数大,移动left指针到中间
left = mid;
else //若中间的数小,移动right指针到中间
right = mid;
}//退出时,left = right -1,left指向左子数组的末尾,right指向右子数组的开头
return nums[right];
}
else //若无旋转,直接返回第一个数
return nums[0];
}
};
/*
其他写法
if (nums[mid] < nums[right]) //这种写法表示,右半段是有序的
right = mid;
else
left = mid;
*/
154. Find Minimum in Rotated Sorted Array II
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).
Find the minimum element.
The array may contain duplicates.
Example 1:
Input: [1,3,5]
Output: 1
Example 2:
Input: [2,2,2,0,1]
Output: 0
Note:
-
Would allow duplicates affect the run-time complexity? How and why?
/*
问题:找旋转有序(增序)数组(含重复数)中的最小数
分析:
旋转后,会形成两个有序左右子数组,且左子数组的数一定比右子数组的数大(或等于)
如[2,2,2,0,1,1,2]
方法:二分查找,遇到相同数字时,left右移一位
平均O(logn),最坏O(n)
*/
class Solution
{
public:
int findMin(vector<int> &nums)
{
if(nums.empty()) return 0;
if(nums.size() == 1) return nums[0];
int res = nums[0];
int left = 0, right = nums.size() - 1;
if(nums[left] >= nums[right]) //若有旋转,由于有重复数字,故这里变为大于等于
{
while (left < right - 1)
{
int mid = (left + right) / 2;
if (nums[left] < nums[mid]) //若中间的数大,移动left指针到中间
{
res = min(res, nums[left]);
left = mid;
}
else if(nums[left] > nums[mid]) //若中间的数小,移动right指针到中间
{
res = min(res, nums[right]);
right = mid;
}
else //若left与mid指向数字相等,将left右移一位,略过相同数字
left++;
}//退出时,left = right -1,left指向左子数组的末尾或右子数组的开头
res = min(res, nums[left]);
res = min(res, nums[right]);
return res;
}
else //若无旋转
return nums[0];
}
};