题目总结:
1.若没有进行旋转,或者说旋转后的效果跟没有旋转是一样的,那么index1指示的值小于index2指示的值,返回index1的值。
2.若是一般性的旋转,那么最小的值旋转后肯定在中间,那么我们就可以从两边向中间夹逼。
3.夹逼的过程中,若 [ index1, middle ] 是有序的,说明这部分子区间没被破坏,旋转所移动的元素都在middle 的后面,那么最小值可定也在后面的部分,令 index1 = middle,继续向后夹逼;同理,若 [ middle ,index2 ] 是有序的,说明这部分子区间也没被最小值破坏,即最小值也没在这里,而应该在前部分,令 index2 = middle,继续向前夹逼,这样两边向中间的收缩,就把最小值确定了。
4.书中说道的 左,中,右相等的时候,无从判断最小值在哪一部分,但可以肯定的是在[ index1, index2] 中,遍历。
int MinInOrder(const vector<int>& nums, int begin, int end){
assert(nums.size() > 0);
int value_min = nums[begin];
while(++begin <= end)
{
if(nums[begin] < value_min)
value_min = nums[begin];
}
return value_min;
}
int Min(const vector<int>& nums){
assert(nums.size() > 0);
int index1 = 0;
int index2 = nums.size() - 1;
int middle = index1;
//if index is still in the front part
while (nums[index1] >= nums[index2])
{
if(index2 - index1 == 1){
middle = index2;
break;
}
middle = (index1 + index2) >> 1;
//can't make sure which part the middle belong to.
if(nums[middle] == nums[index1] &&
nums[middle] == nums[index2])
return MinInOrder(nums, index1, index2);
//the front part is in order
else if(nums[middle] >= nums[index1])
index1 = middle;
//the back part is in order.
else if(nums[index2] >= nums[middle])
index2 = middle;
}
return nums[middle];
}
除了找最小值,还可以找最大值,思路和这一样,就是找两个区间的断裂处。
这里给定的是一个经过选择的数组,我们试着自己实现下这种旋转。
函数接口如下:
void RotaArray(vector<int>& nums, int roteNums)
nums:给定的要旋转的数组。
roteNums:表示数组的前 roteNums 个数移动到数组的后面。
分析:
我们开始将旋转的两部分视为两个元素,那么目标就是交换着两个元素的位置,看来是要用到交换。
比如 1, 2, 3, 4, 5,将前两个交换到后面,变成 3, 4, 5, 1, 2.
我们首先不管其他交换一下看看。
首尾交换我们得到:5,4,3,2,1.
虽然 1,2 确实到了数组的后面,但是 5,4,3,区间 和 2,1区间是反的。但再看之下,我们发现,在把两个区间各自内部交换下就行了。
5,4,3交换,得到:3, 4, 5
2,1交换,得到:1, 2.
这样就得到:3 ,4 ,5 ,1, 2.
当然先对子区间内部交换再整体交换也是一样的。
void Swap(int& a, int& b){
a ^= b;
b ^= a;
a ^= b;
}
void Reverse(vector<int>& nums, int begin, int end){
if(begin < 0 || end > nums.size())
return;
while (begin < end)
{
Swap(nums[begin++], nums[end--]);
}
}
void RotaArray(vector<int>& nums, int roteNums){
if(nums.size() <= 1 || roteNums == 0 || roteNums >= nums.size())
return;
Reverse(nums, 0, roteNums - 1);
Reverse(nums, roteNums, nums.size() - 1);
Reverse(nums, 0, nums.size() - 1);
}