编程之美3:寻找数组中的最大值和最小值以及最大值和次大值

很开心,这是今天的第三篇文章啦!下午健身也感觉非常过瘾,托付宿舍妹子从日本代购的护肤品也到了。耳边漂浮着Hebe田馥甄的《魔鬼中的天使》文艺的声线,一切都好棒,O(∩_∩)O哈哈~。爱生活,爱音乐,爱运动,额,当然还有要爱学习啦!加油(^ω^)

额,扯远了。第三篇是关于寻找数组中的最大值和最小值。第一次看到这个题目的时候,楼主稍微鄙视了一下,因为觉得这个题目有什么好做的。但是楼主还是看了看《编程之美》上的写的,发现还是有必要记录一下,不一样的思考方式。很赞!大家和楼主一起哦,Are you ready?呼呼(~ o ~)~zZ

题目一:寻找数组中的最大值和最小值

解法一

把寻找数组中的最大值和最小值看成是两个独立的问题,对于每个独立的问题的话,我们可以采用一次循环遍历的方法得到。假设数组的长度为N,那么总共需要比较的次数为2N。解法过于简单,代码略过啦。

解法二

假设数组为[5, 6, 8, 3, 7, 9],

  • 每相邻的两个元素比较,较大者放在偶数位,较小者放在奇数位。完成这一步骤后,偶数位为6, 8, 9。奇数位为5, 3, 7。
  • 然后遍历偶数位可以获得数组的最大值,遍历奇数位可以获得数组的最小值。
  • 比较次数:0.5N+0.5N+0.5N=1.5N看代码:
#include <iostream>
#include<limits>

using namespace std;  

void partion(int *pArray, int len);

int main()
{
    int a[] = {1, 2, 3, 4, 5, 6, 0, 7};
    int len = sizeof(a) / sizeof(int);
    partion(a, len);
    int MAX = a[0];
    int MIN = a[1];

    int i = 0;
    int j = 1;

    for (; i < len - 1, j < len; i = i + 2, j = j + 2)
    {
        if (a[i] > MAX)
        {
            MAX = a[i];
        }
        if (a[j] < MIN)
        {
            MIN = a[j];
        }
    }

    //说明有一个数单出来
    if (i == len - 1)
    {
        if (a[i] > MAX)
        {
            MAX = a[i];
        }
        if (a[i] < MIN)
        {
            MIN = a[i];
        }
    }

    cout << "最小值为" << MIN << " 最大值为" << MAX << endl;
    system("pause");
}  

//将数组分成两个子数组,较大值放在偶数位,较小值放在奇数位
void partion(int *pArray, int len)
{
    int i = 0;
    while (i < len - 1)
    {
        //如果奇数位的比偶数位的大,则交换位置
        if ((pArray[i + 1] > pArray[i]))
        {
            swap(pArray[i + 1], pArray[i]);
        }
        i += 2;
    }
}

解法三

解法二虽然降低了比较的次数,可是却破坏了数组的顺序。绝大多数时候,我们只是想获取数组中的最大值和最小值,并没有想要改变数组的顺序,所以解法二,会有问题。那这就是解法三改进的点了,同样和解法二一样,每相邻的两个元素进行比较,但是不改变数组的顺序。而是选择用两个变量,如MAX和MIN来记录最大值和最小值并看情况更新。看下图所示

看代码:

#include <iostream>
#include<limits>

using namespace std;  

void searchMinAndMax(int *pArray, int low, int high, int *MIN, int *MAX);

int main()
{
    int a[] = {9, 8, 7, 6, 5, 4, 3, 11, 12, 13, 1, 1, 13, 67, 89, 0,100, -1};
    int len = sizeof(a) / sizeof(int);
    int MIN = numeric_limits<int>::max();;
    int MAX = 0;
    int tempMin = 0;
    int tempMax = 0;
    int i = 0;
    while (i < len - 1)
    {
        if ((a[i] >= a[i + 1]))
        {
            tempMax = a[i];
            tempMin = a[i + 1];
        }
        else
        {
            tempMax = a[i + 1];
            tempMin = a[i];
        }
        if (tempMax > MAX)
        {
            MAX = tempMax;
        }
        if (tempMin < MIN)
        {
            MIN = tempMin;
        }
        i += 2;
    }
    if (i == len - 1)
    {
        if (a[i] < MIN)
        {
            MIN = a[i];
        }
        if (a[i] > MAX)
        {
            MAX = a[i];
        }
    }

    cout << "最小值为" << MIN << " 最大值为" << MAX << endl;
    system("pause");
}  

解法四

分治法,把N个元素的最大值和最小值问题,分别求出N/2维左半部分和右半部分的最大值和最小值。左半部分最大值和右半部分最大值比较,较大值为最后的最大值;同样,左半部分的最小值和右半部分的最小值比较,较小者为最后的最小值。看代码:

#include <iostream>  

using namespace std;  

void searchMinAndMax(int *pArray, int low, int high, int *MIN, int *MAX);

int main()
{
    int a[] = {9, 8, 7, 6, 5, 4, 3, 11, 12, 13, 1, 1, 13, 67};
    int len = sizeof(a) / sizeof(int);
    int MIN = 0;
    int MAX = 0;
    searchMinAndMax(a, 0, len-1, &MIN, &MAX);
    cout << "最小值为" << MIN << " 最大值为" << MAX << endl;
    system("pause");
}  

void searchMinAndMax(int *pArray, int low, int high, int *MIN, int *MAX)
{
    int middle = (low + high) / 2;

    //如果分组只剩下两个数字或者一个数字,则直接比较
    if (high - low <= 1)
    {
        if (pArray[low] > pArray[high])
        {
            *MIN = pArray[high];
            *MAX = pArray[low];
            return;
        }
        else
        {
            *MIN = pArray[low];
            *MAX = pArray[high];
            return;
        }
    }

    int lMin = 0;
    int lMax = 0;
    int rMin = 0;
    int rMax = 0;

    searchMinAndMax(pArray, low, middle, &lMin, &lMax);
    searchMinAndMax(pArray, middle + 1, high, &rMin, &rMax);

    *MIN = min(lMin, rMin);
    *MAX = max(lMax, rMax);
}

需要比较的次数为1.5N?2。

题目二:寻找数组中的最大值和次大值

这道题是《编程之美》上题目一的扩展问题,为了巩固前面的知识,楼主决定把这道题也给做了,运用分治思想。主要思想和题目一类似。直接看代码:

#include <iostream>  

using namespace std;  

void searchMinAndMax(int *pArray, int low, int high, int *MIN, int *MAX);

int main()
{
    int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 67};
    int len = sizeof(a) / sizeof(int);
    int MAX = 0;
    int SECONDE_MAX = 0;
    searchMinAndMax(a, 0, len-1, &SECONDE_MAX, &MAX);
    cout << "最大值为" << MAX << " 次大值为" << SECONDE_MAX << endl;
    system("pause");
}  

void searchMinAndMax(int *pArray, int low, int high, int *SECONDE_MAX, int *MAX)
{
    int middle = (low + high) / 2;

    //如果分组只剩下两个数字或者一个数字,则直接比较
    if (high - low <= 1)
    {
        if (pArray[low] > pArray[high])
        {
            *SECONDE_MAX = pArray[high];
            *MAX = pArray[low];
            return;
        }
        else
        {
            *SECONDE_MAX = pArray[low];
            *MAX = pArray[high];
            return;
        }
    }

    int lSeMax = 0;
    int lMax = 0;
    int rSeMax = 0;
    int rMax = 0;

    searchMinAndMax(pArray, low, middle, &lSeMax, &lMax);
    searchMinAndMax(pArray, middle + 1, high, &rSeMax, &rMax);

    *SECONDE_MAX = max(lSeMax, rSeMax);
    *MAX = max(lMax, rMax);
}

比较次数也是1.5N?2

楼楼这篇文章就到此为止啦,还剩下三篇就可以开专栏了哦。加油加油!!!希望大家一天都充满活力,O(∩_∩)O哈哈~

时间: 2024-10-05 20:08:54

编程之美3:寻找数组中的最大值和最小值以及最大值和次大值的相关文章

编程之美2.17 数组循环移位

问题描述: 设计一个算法,把一个含有N元素的数组循环左移或者右移K位. 解决方法: 1. 暴力解法------O(KN) 2. 颠倒位置------O(N) 具体思路和代码: 1. 暴力解法------O(KN) 思路:循环K次,每次移动一位 代码: 1 //右移 2 void s1(int A[], int n, int k) 3 { 4 k = k % n; 5 for(int i = 0; i < k; i++) 6 { 7 int t = A[n-1]; 8 for(int j = n-

【编程之美】寻找数组中的最大值和最小值

数组是最简单的一种数据结构.我们经常碰到的一个基本问题,就是寻找整个数组中最大的数,或者最小的数.这时,我们都会扫描一遍数组,把最大(最小)的数找出来.如果我们需要同时找出最大和最小的数呢? 对于一个由N个整数组成的数组,需要比较多少次才能把最大和最小的数找出来呢? 分析与解法 解法一:分别求最大和最小值 可以分别求出数组的最大值和最小值,这样,我们需要比较2N次才能求解. 解法二:分组求解 (1) 按顺序将数组中相邻的两个数分在同一组: (2) 比较同一组的两个数,将大的数放在偶数位上,小的放

编程之美2.18—数组分割

题目: 有一个没有排序,元素个数为2N的正整数数组.要求把它分割为元素个数为N的两个数组,并使两个子数组的和最接近. 基本思想: 假设数组A[1..2N]所有元素的和是SUM.模仿动态规划解0-1背包问题的策略,令S(k, i)表示前k个元素中任意i个元素的和的集合. 显然: S(k, 1) = {A[i] | 1<= i <= k} S(k, k) = {A[1]+A[2]+-+A[k]} S(k, i) = S(k-1, i) U {A[k] + x | x属于S(k-1, i-1) }

编程之美2.17—数组循环移位(旋转数组)

题目: 把一个含有N个元素的额数组循环右移K位,要求时间复杂度O(N),且只允许使用两个附加变量. 解法一:O(N^2) 每次将数组中的元素右移移位,循环K次.当K>N时,右移K位和右移K%N位是一样的. MyShift(int a[],int N,int K) { K%=N; while(K--) { int t=a[N-1]; for(int i=N-1;i>0;i--) a[i]=a[i-1]; a[0]=t; } } 解法二:O(N) 假如数组abcd1234 1.逆序abcd:abc

编程之美6:数组循环移位

楼主又来~(≧▽≦)/~啦啦啦,科研,就是要这么一鼓作气.额,其实楼主的老本行是推公式啊,做这些算法题,其实是楼主在偷懒.额,话不多说了,快请出我们今天的主角吧!还是关于数组的-数组循环移位. 下面我们来看下题目的要求. 题目要求: 设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量. 题目解答 我们来自己给个例子,来帮助自己思考.如数组为[1, 2, 3, 4, 5, 6, 7, 8],循环移位4次. 原始序列:[1, 2, 3, 4, 5,

编程之美2.18 数组分割 原创解O(nlogn)的时间复杂度求解:

题目:有一个无序.元素个数为2n的正整数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并使两个子数组的和最接近? 1 1 2 -> 1 1 vs  2 看题时,解法的时间复杂度一般都大于或等于O(n^2).突然灵感一闪,发现一个新的解法,应该算是一个动态规划的过程吧,思路比较简单,请看代码.空间复杂度O(nlogn),时间复杂度O(n).但是不能确定是否适用所有正整数组,如果有错,请给出你的测试用例,谢谢! 代码如下: 1 1 #include <iostream> 2 2 #

编程之美3.7 队列中最大值问题

      这道题目的意思是,有一个队列,它里面会存储一些数值,现在,要求你需要在 O(1) 的时间内返回这个队列中最大的那个值.       这道题目的和栈中最大值最小值问题是一样的解法,都是需要一个辅助的东西,对于这道题目,我需要的是一个辅助队列.       由于是需要找到最大值,我的做法是,如果辅助队列为空,那么,当数据入队列的时候就需要同时放入队列和辅助队列中:如果辅助队列不为空,但是入队列的那个元素比辅助队列的队首元素大或者相等,那么,也是需要同时放入两个队列中:其他情况,只需要放入

寻找数组中第k个最小值,使用快速排序

快速排序的一个特点是:每一次分区(partition)操作之后,就有一个元素被放在了数组的最终位置,在以后的排序过程中该元素位置不会变动: 利用这个特点我们可以将快速排序稍加改造来寻找第k个最小值,假设在一次分区操作之后中枢(pivot)的位置在k之前,那么我们下次只需要在中枢的后面进行查找:如果中枢的位置在k之后,那么我们下次只需要在中枢之前进行查找,直到中枢等于k为止. 我们知道快速排序的时间复杂度为O(nlgn),因为在寻找第k个最小的值时,我们只需要在中枢的一侧进行查找,所以通常来说这个

编程之美2.10 寻找数组中的最大值和最小值

这个问题其实很容易解决,就是循环遍历一遍数组,然后找到数组中存在的最大值和最小值就可以了,书中主要讨论的问题是比较次数较小的方法,不过,书中已经证明了,无论用什么方法最少的比较次数也就是循环遍历一遍的比较,结果是O(1.5N)的,所以,很容易的可以解决这个问题. 第一种方法: 函数声明: void DutFindMaxAndMinInArray_1(int*, int, int&, int&); 源代码如下: /*基本的解法寻找最大值和最小值*/ bool _DutFindMaxAndMi