题目总结:
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); }
【剑指offer】旋转数组中的最小值,布布扣,bubuko.com