假设按照升序排序的数组在预先未知的某个点上进行了旋转。例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] 。
请找出其中最小的元素。
示例 1:
输入:nums = [3,4,5,1,2]
输出:1
示例 2:
输入:nums = [4,5,6,7,0,1,2]
输出:0
示例 3:
输入:nums = [1]
输出:1
来源:力扣(LeetCode)
2.1 思路
本思路是概括了题目和修改后的题目,暴力破解都是这个方法。
原数组是非递减的,旋转后,有两种情况,数组仍是非递减的,例如将全部元素放到数组的末尾,它相当于还是原数组,或者有重复项,例如 {2,2,2,2},旋转后仍是非递减的,那么我们返回第一个元素即可。另一种情况就会出现前一个元素大于后一个元素,那么后一个元素一定是最小的,也就是我们要的解。
2.2 代码
int findMin(vector<int>& nums) {
if(!nums.size()) return -1;
for(int i = 0; i < nums.size() - 1; i++) {
if(nums[i] > nums[i + 1])
return nums[i + 1];
}
return nums[0];
}
3.1 思路
此思路是假设没有重复的数。
我们知道,当数组是已经排序好的,我们可以用二分法来查找,其实本题也可以利用二分法来做。
我们找一个中间值,如果这个中间值小于此时的left,那么就意味着我们要找的数就在left 到 mid 中间,如果中间值大于left,那么我们要找的值就在mid到right中间,直到缩减到两个数的时候,此时左指针指向的数一定大于右指针指向的数,mid此时就会在左指针的位置上,我们返回右指针即可
3.2 代码
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0;
int right = nums.size() - 1;
int mid = (left + right) / 2;
if (nums[left] < nums[right])
{
return nums[left];
}
while (left != mid)
{
if (nums[mid] > nums[left])
{
left = mid;
}
else if (nums[mid] < nums[right])
{
right = mid;
}
mid = (left + right) / 2;
}
return nums[right];
}
};
4.1题目
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个升序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
数组可能包含重复项。
注意:数组内所含元素非负,若数组大小为0,请返回-1。
样例
输入:nums=[2,2,2,0,1]
输出:0
题目地址
4.2解法
题目中允许出现重复的数字,这就意味着在原来的理解上我们要多一层可能,那就是中间的值等于左侧值或者右侧的值,举一个例子[2,2,2,1,1,2],此时mid指向第三个2,最小值在mid的右侧;[2,2,2,1,1,2,2,2,2,2,2],此时最小值在mid左侧。这样我们就需要来判断此时我们是要在左侧寻找还是在右侧寻找了。但不管怎么样,如果相同,我们可以省略掉相同的数的那个指针。
所以分三种情况,当中间的比最右端的小,此时我们让右指针移动过来,当中间的比右边打,我们让左指针移到中间指针的后方,如果相等,就让右指针移动。
4.3代码
class Solution {
public:
int findMin(vector<int>& nums) {
int low = 0;
int high = nums.size() - 1;
while (low < high) {
int pivot = low + (high - low) / 2;
if (nums[pivot] < nums[high]) {
high = pivot;
}
else if (nums[pivot] > nums[high]) {
low = pivot + 1;
}
else {
high -= 1;
}
}
return nums[low];
}
};