题目
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个升序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
数组可能包含重复项。
注意:数组内所含元素非负,若数组大小为0,请返回-1。
样例
输入:nums=[2,2,2,0,1]
输出:0
解法:二分

旋转过后数组分成如上图所示的两段,满足这样的二分性质:第一段>=nums[0],第二段
由于数组中可能存在重复,因此一开始需要先把第二段末尾和第一段开头重复的部分去掉,确保二分性质成立
还需要注意没有旋转的情况
时间复杂度O(n),空间复杂度O(1)
class Solution {public:int findMin(vector<int>& nums) {if (nums.empty()) return -1;int n = nums.size() - 1;while (n && nums[n] == nums[0]) n--;if (nums[n] >= nums[0]) return nums[0]; // 剩下的部分完全单调int l = 0, r = n;while (l < r) {int mid = l + r >> 1;if (nums[mid] < nums[0])r = mid;else l = mid + 1;}return nums[l];}};
补充
旋转数组中的查找
旋转数组定义和上面一致,区别在于从最小值变成了查找
可以根据nums[mid]和nums[0], k之间的关系分类讨论
时间复杂度O(logn),空间复杂度O(1)
// #define SUBMIT#include <time.h>#include <iostream>using namespace std;const int N = 110;int a[N];int main() {#ifdef SUBMITfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);long _begin_time = clock();#endifint n, k;cin >> n >> k;for (int i = 0; i < n; i++)scanf("%d", &a[i]);int l = 0, r = n - 1;while (l < r) {int mid = l + r + 1 >> 1;if (a[mid] < a[0]) {if (a[mid] <= k && k <= a[n - 1])l = mid;elser = mid - 1;}else {mid = l + r >> 1;if (a[mid] >= k && k >= a[0]) {r = mid;}elsel = mid + 1;}}if (a[l] == k) cout << l;else cout << -1;#ifdef SUBMITlong _end_time = clock();printf("\n\ntime = %ld ms", _end_time - _begin_time);#endifreturn 0;}
