有序数组旋转的问题

来源:互联网 发布:软件培训会议纪要 编辑:程序博客网 时间:2024/06/04 19:08

1、有序数组旋转后寻找数组中的最小值

一般情况下我们的第一反应肯定是遍历此数组,但这肯定不是我们所期望的,因为此数组是有序数组旋转而成,所以我们此时应该想到用二分法来寻找数组中的最小值。假设我们给定递增数组{0,1,2,3,4,5,6,7,8,9}

旋转后的数组有下面几种形式

{6,7,8,9,0,1,2,3,4,5}

{9,0,1,2,3,4,5,6,7,8}
{0,1,2,3,4,5,6,7,8,9}
{5,6,7,8,9,0,1,2,3,4}
通过观察可以发现,在经过旋转后的数组在寻找最小值的过程中0的前面的数总是大于0后面的数,所以我们可以以此为条件,在将范围缩小为2个数时,后面的数就是最小值,根据此思路代码如下:

<span style="font-family:Microsoft YaHei;font-size:14px;">int MinArray(int* a, int n){assert(a != NULL || n <= 0);int start = 0;int end = n - 1;int mid = start;while (a[start] >= a[end])  //确定数组经过旋转已经不是有序数组{if (end - start == 1) //当只剩两个数时直接返回较小值的下标{mid = end;break;}mid = (start + end) / 2;//如果a[start],a[mid],a[end]相等时,只能遍历寻找最小值if (a[mid] == a[start] && a[mid] == a[end]){int min = a[start];while (start <= end){if (a[start] < min){mid = a[start];}++start;}return min;}if (a[mid] >= a[start]){start = mid;}else if (a[mid] <= a[end]){end = mid;}}return a[mid];}</span>


上面的程序已经将一种特殊情况给处理了,例如下面这种例子
{1,0,1,1,1}
{1,1,1,0,1}
此时若直接进行比较,将会出现将最小值跳过的情况,所以我们在此种情况下只能采取遍历寻找最小值。
我们也可以使用下标的方式来实现寻找最小值,思路和上面的程序一样,代码如下:
<span style="font-family:Microsoft YaHei;font-size:14px;">int MinArray2(int* a, int n){assert(a != NULL || n <= 0);int start = 0;int end = n - 1;while (start < (start+end)/2)  {int mid = (start + end) / 2;//如果a[start],a[mid],a[end]相等时,只能遍历寻找最小值if (a[mid] == a[start] && a[mid] == a[end]){int min = a[start];while (start <= end){if (a[start] < min){mid = a[start];}++start;}return min;}if (a[mid] >= a[start] && a[mid] <= a[end])  //此时数组有序,直接返回数组下标0{return 0;}if (a[mid] >= a[start]){start = mid;}else if (a[mid] <= a[end]){end = mid;}}if (a[start] > a[end]){return a[end];}return a[start];}</span>

上面是求去旋转有序数组的最小值,求最大值的思路和最小值的一样,只需要在循环结束返回时返回那个较大值即可。

2、有序数组旋转后给定数值返回此数值在数组中的下标

实现在一个旋转有序数组中寻找一个数并返回下标,很多人的第一反应肯定是直接遍历,但这样的话有序数组旋转的特性没有得到应用,所以我们需要分析旋转有序数组的特点,例如下面旋转有序数组
{5,6,7,8,9,0,1,2,3,4}
{6,7,8,9,0,1,2,3,4,5}
{0,1,2,3,4,5,,6,7,8,9}
通过观察上面的数组我们可以发现无论数组如何旋转,数组分成两个子数组时,一个肯定是有序的,所以我们可以利用此特性来实现寻找一个特定的数,每次将给定数值通过和有序数组的首尾两个值对比,来判断此数是否存在在这个数组中,如果在的话,将此数组递归,若不在,将另一个数组递归,重复此过程,直至首尾元素下标相同,或寻找到此给定数值。
依据上面的思路实现的代码如下:
<span style="font-family:Microsoft YaHei;font-size:14px;">int Search(int* a, int n, int x){assert(a != NULL || x <= 0);int start = 0;int end = n - 1;while (start < end){int mid = (start + end) / 2;if (a[mid] == x){return mid;}else if (a[mid] > a[start]){if (x <= a[mid] && x >= a[start]){end = mid;}else{start = mid;}}else if (a[end] > a[mid]){if (x >= a[mid] && x <= a[end]){start = mid;}else{end = mid;}}else{++start; //处理数组中有重复的数字}}return -1;}</span>


0 0
原创粉丝点击