题目:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0
思路:
方案一:简单的知己遍历查找:时间复杂度:O(n),空间O(1)
因为题目中所提供的是一个排序的原始数组,因此我们只要循环一次,找到变小的那个元素,这个元素就是最小元素;如果如果没有,那么第一个元素就是我们要找的元素了;
从给这个方案中的思考中,我们知道代码中要对 未经旋转的数组进行处理,不妨设置一个测试用例为
[1,2,3,4,5];
方案二:快排思想/ 二分思想 / 切分数组:时间复杂度:O(logn), 空间O(1)
对于[3,4,5,1,2], 他是两段连续增长的数组拼接而成的
我们取 起始点、中点、 终止点三个点进行比较,3 > 5 && 5 > 2
可见第一段是递增的,而第二段显然并非递增,因此最小值在第二段中;
我们重复这个过程,5 > 1 && 1 < 2,第一段不是递增的,因此对第一段继续;
而此时这两个元素只相差1个下标,因此这段中的第二个值就是我们要的最小值;
据此不难实现如下代码:
while(last - first >= 1){
if(last - first == 1)
return numbers[last];
int mid_index = (first + last)/2;
// 注释一:
// if(numbers[first] == numbers[last] && numbers[first] == numbers[mid_index]){
// return find_byOrder(numbers);
// }
if(numbers[first] > numbers[mid_index]){
last = mid_index;
}
else if(numbers[last] < numbers[mid_index]){
first = mid_index;
}
}
return numbers[0]; // 注释2
对于刚刚说的测试用例 [1,2,3,4,5],这并不能满足,对于原地旋转的情况我们没有判断,其实只需要在return的时候:注释二;
对于小于等于3个元素的数组呢?while中的判断条件也有问题:旋转过后的数组的特点就是 first的数值要大于last,因此修改为:numbers[first] >= numbers[last]
还有一点细节!如果最初的 first 、last、mid_index对应的数值都相等怎么办?
这将不会进行任何操作,一直循环
比如:【1,0,1,1,1,1】
这时可能有一些其他的办法,这里我直接调用方法一函数,遍历查找;
方法二:代码:
class Solution {
public:
int find_byOrder(vector<int>& numbers){
int index = 0;
for(int i = 1; i< numbers.size(); i++)
{
if(numbers[i] < numbers[i - 1]) {
index = i;
}
}
return numbers[index];
}
int minArray(vector<int>& numbers) {
if(numbers.size() == 0)
return -9999;
int first = 0, last = numbers.size()-1;
while(numbers[first] >= numbers[last]){
if(last - first == 1)
return numbers[last];
int mid_index = (first + last)/2;
if(numbers[first] == numbers[last] && numbers[first] == numbers[mid_index]){
return find_byOrder(numbers);
}
if(numbers[first] > numbers[mid_index]){
last = mid_index;
}
else if(numbers[last] < numbers[mid_index]){
first = mid_index;
}
}
return numbers[0];
}
};