首页 > 代码库 > 【剑指offer】旋转数组中的最小值

【剑指offer】旋转数组中的最小值

题目总结:

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);
}