• 题目:旋转数组的最小数字


    题目描述:

      把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。

    旋转数组的特点:

      (1)旋转之后的数组实际上可以划分为两个排序的子数组,且前面的子数组的元素都大于或者等于后面子数组的元素。(有一个特例,后面说明!)

      (2)最小的元素刚好是这两个数组的分界线。

      (3)旋转数组在一定程度上是排序的,因此可以用二分查找法的思路来寻找这个最小的元素。

    思路:

      (1)设置两个指针,初始状态第一个指针指向前面子数组的第一个元素,第二个指针指向后面子数组的最后一个元素;

      (2)找到两个指针的中间元素;

      (3)若其大于等于第一个指针指向的元素,则说明其在前面的子数组中,且显然最小元素在中间元素的右边,若其小于等于第二个指针指向的元素,则说明其在后面的子数组中,且显然最小元素在中间元素的左边。如此,便可以缩小搜索范围,最终第一个指针指向前面子数组的最后一个元素,而第二个指针指向后面子数组的第一个元素,它们处于相邻位置,而第二个指针指向的刚好是最小的元素

      以题目举例的数组{3,4,5,1,2}分析,先把第一个指针指向第0个元素,把第二个指针指向第4个元素(如图2.10(a)所示)。位于两个指针中间(在数组中的下标是2)的数字是5,它大于第一个指针指向的数字。因此中间数字5一定位于第一个递增子数组中,并且最小的数组一定位于它的后面。因此可以移动第一个指针让它指向数组的中间(如图2.10(b)所示)。

      此时位于这两个指针中间(在数组中的下标是3)的数字是1,它小于第二个指针指向的数字。因此这个中间数字1一定位于第二个递增子数组中,并且最小的数字一定位于它的前面或者它自己就是最小的数字。因此可以移动第二个指针指向两个指针中间的元素,即下标为3的元素(如图2.10(c)所示)。

      注:旋转数组中包含两个递增排序的子数组,有阴影背景的是第二个子数组。

       (a)把P1指向数组的第一个数字,P2指向数组的最后一个数字。由于P1和P2中间的数字5大于P1指向的数字,中间的数字在第一个子数组中。下一步把P1指向中间的数字。

       (b)P1和P2中间的数字1小于P2指向的数字,中间的数字在第二个子数组中。下一步把P2指向中间的数字。

         (c)P1和P2指向两个相邻的数字,则P2指向的是数组中的最小数字。

      此时两个指针的距离是1,表明第一个指针已经指向了第一个递增子数组的末尾,而第二个指针指向第二个递增子数组的开头。第二个子数组的第一个数字就是最小的数字,因此第二个指针指向的数字就是我们查找的结果。

      注意两点:

      (1)按旋转规则,第一个元素应该是大于或等于最后一个元素的;但也有特例:若把排序数组的前0个元素搬到最后面,及排序数组本身,仍是数组的一个旋转,此时数组中的第一个数字是最小的数字,应该直接返回。

      (2)当两个指针指向的数字及它们中间的数字三者相等时,无法判断中间数字位于前面的子数组还是后面的子数组,也就无法移动两个指针来缩小查找的范围,此时只能用顺序查找的方法。

      例如:数组{1,0,1,1,1}和数组{1,1,1,0,1}都可看成是递增数组{0,1,1,1,1}的旋转。第一种情况,中间数字位于后面的子数组,第二种情况,中间数字位于前面的子数组。

      

     

    鉴于此,实现的代码如下:

     1 /*
     2 Time:2016-9-21 17:01:41
     3 Author:CodingMengmeng
     4 */
     5 #include <iostream>
     6 using namespace std;
     7 
     8 int Min(int* data, int length);
     9 int MinInOrder(int* data, int index1, int index2);
    10 
    11 int main()
    12 {
    13 //    int nArr1[5] = { 3, 4, 5, 1, 2 }; 
    14     int nArr1[10] = { 5, 6, 6, 7, 7, 8, 9, 2, 3, 4 };
    15     cout << "the minimum value in nArr1 is " << Min(nArr1,10)<< endl;
    16     int nArr2[5] = { 1, 0, 1, 1, 1 };
    17     cout << "the minimum value in nArr2 is " << Min(nArr2, 5) << endl;
    18     int nArr3[5] = { 1, 1, 1, 0, 1 };
    19     cout << "the minimum value in nArr3 is " << Min(nArr3, 5) << endl;
    20     int nArr4[5] = { 1, 2, 3, 4, 5 };
    21     cout << "the minimum value in nArr4 is " << Min(nArr4, 5) << endl;
    22     int* nArr5 = NULL;
    23     cout << "the minimum value in nArr5 is " << Min(nArr5, 5) << endl;
    24 
    25     system("pause");
    26     return 0;
    27 }
    28 
    29 int Min(int* data, int length)
    30 {
    31     if (data == NULL || length <= 0)
    32         throw new exception("Invalid parameters!");
    33     int index1 = 0;
    34     int index2 = length - 1;
    35     int indexMid = index1;
    36     //若把排序数组的前0个元素搬到最后面,及排序数组本身,
    37     //仍是数组的一个旋转,此时数组中的第一个数字是最小的数字,应该直接返回。
    38     //显然这种情况不满足while循环,所以直接返回。
    39     while (data[index1] >= data[index2])
    40     {
    41         /*
    42         两个指针的距离是1,表明第一个指针已经指向了第一个递增子数组的末尾,
    43         而第二个指针指向第二个递增子数组的开头。
    44         第二个子数组的第一个数字就是最小的数字,
    45         因此第二个指针指向的数字就是我们查找的结果。
    46         */
    47         if (index2-index1==1)
    48         {
    49             indexMid = index2;
    50             break;
    51         }
    52         indexMid = (index1 + index2) / 2;
    53         /*
    54         当两个指针指向的数字及它们中间的数字三者相等时,
    55         无法判断中间数字位于前面的子数组还是后面的子数组,
    56         也就无法移动两个指针来缩小查找的范围,此时只能用顺序查找的方法。
    57         */
    58         if (data[index1] == data[index2] && data[indexMid] == data[index1])
    59             return MinInOrder(data, index1, index2);
    60         if (data[indexMid] >= data[index1])
    61             index1 = indexMid;
    62         else if (data[indexMid] <= data[index2])
    63             index2 = indexMid;
    64     }
    65     return data[indexMid];
    66 }
    67 
    68 int MinInOrder(int* data, int index1, int index2)
    69 {
    70     int MinResult = data[index1];
    71     for (int i = index1 + 1; i <= index2; i++)
    72     {
    73         if (MinResult > data[i])
    74             MinResult = data[i];
    75     }
    76     return MinResult;
    77 }

      运行结果:

      

      nArr5由于出现异常,在运行结果中未显示!

  • 相关阅读:
    Nginx的日志剖析
    黑帽大会:苹果网络服务器比微软易入侵 狼人:
    美国安全局大力招募黑客 狼人:
    微软MAC地址数据库惊爆安全门:任何人都可以定位你 狼人:
    云网络被广泛应用 企业SaaS选型面临五大安全问题 狼人:
    华为聘请英国政府前CIO为首任全球网络安全官 狼人:
    莫使微博成黑客“投毒”新渠道 狼人:
    黑帽大会:Windows密码存储机制存在漏洞 狼人:
    思科增强云计算效率与安全性 狼人:
    德国安全专家成功破解GPRS加密算法 狼人:
  • 原文地址:https://www.cnblogs.com/codingmengmeng/p/5893376.html
Copyright © 2020-2023  润新知