[程序员面试题精选100题]61.数对之差的最大值

简介:

题目

在数组中,数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值。例如在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果。

思路一

看到这个题目,很多人的第一反应是找到这个数组的最大值和最小值,然后觉得最大值减去最小值就是最终的结果。这种思路忽略了题目中很重要的一点:数对之差是一个数字减去它右边的数字。由于我们无法保证最大值一定位于数组的左边,因此这个思路不管用。

于是我们接下来可以想到让每一个数字逐个减去它右边的所有数字,并通过比较得到数对之差的最大值。由于每个数字需要和它后面的O(n)个数字作减法,因此总的时间复杂度是O(n^2)。

思路二

利用动态规划实现:
设dp[i]为第i个元素(包括第i个元素)之前元素的最大值。
动态规划方程为:

dp[i] = max(dp[i-1],num[i])

时间复杂度:O(n)
空间复杂度:O(n)

代码二

    /*-------------------------------------
    *   日期:2015-03-25
    *   作者:SJF0115
    *   题目: 61.数对之差的最大值
    *   来源:程序员面试题精选100题
    *   博客:
    ------------------------------------*/
    #include <iostream>
    #include <vector>
    using namespace std;

    int MaxDiff(int num[],int n){
        if(n <= 1){
            return 0;
        }//if
        vector<int> dp(n,0);
        // 计算i之前元素的最大值(包括第i个元素)
        dp[0] = num[0];
        for(int i = 1;i < n;++i){
            dp[i] = max(dp[i-1],num[i]);
        }//for
        // 计算最大的数对之差
        int Max = num[0] - num[1];
        for(int i = 2;i < n;++i){
            Max = max(Max,dp[i-1] - num[i]);
        }//for
        return Max;
    }

    int main(){
        int num[] = {2,4,1,16,7,5,11,9};
        cout<<MaxDiff(num,8)<<endl;
        return 0;
    }

思路三

对上面的思路进行优化一下。
我们不单独开辟一个数组来存储当前元素之前的最大元素值,而是利用当前元素的前一个位置来记录当前元素之前的最大值。

时间复杂度:O(n)
空间复杂度:O(1)

代码三

    /*-------------------------------------
    *   日期:2015-03-25
    *   作者:SJF0115
    *   题目: 61.数对之差的最大值
    *   来源:程序员面试题精选100题
    *   博客:
    ------------------------------------*/
    #include <iostream>
    #include <vector>
    using namespace std;

    int MaxDiff(int num[],int n){
        if(n <= 1){
            return 0;
        }//if
        // 计算最大的数对之差
        int Max = num[0] - num[1];
        num[1] = max(num[0],num[1]);
        for(int i = 2;i < n;++i){
            Max = max(Max,num[i-1] - num[i]);
            num[i] = max(num[i-1],num[i]);
        }//for
        return Max;
    }

    int main(){
        int num[] = {2,4,1,16,7,5,21,9};
        //int num[] = {1,2,3,4,5,6,7,8};
        cout<<MaxDiff(num,8)<<endl;
        return 0;
    }

思路四 分治法

通常蛮力法不会是最好的解法,我们想办法减少减法的次数。假设我们把数组分成两个子数组,我们其实没有必要拿左边的子数组中较小的数字去和右边的子数组中较大的数字作减法。我们可以想象,数对之差的最大值只有可能是下面三种情况之一:(1)被减数和减数都在第一个子数组中,即第一个子数组中的数对之差的最大值;(2)被减数和减数都在第二个子数组中,即第二个子数组中数对之差的最大值;(3)被减数在第一个子数组中,是第一个子数组的最大值。减数在第二个子数组中,是第二个子数组的最小值。这三个差值的最大者就是整个数组中数对之差的最大值。

在前面提到的三种情况中,得到第一个子数组的最大值和第二子数组的最小值不是一件难事,但如何得到两个子数组中的数对之差的最大值?这其实是原始问题的子问题,我们可以递归地解决。

代码四

int MaxDiff_Solution1(int numbers[], unsigned length)
{
    if(numbers == NULL || length < 2)
        return 0;

    int max, min;
    return MaxDiffCore(numbers, numbers + length - 1, &max, &min);
}

int MaxDiffCore(int* start, int* end, int* max, int* min)
{
    if(end == start)
    {
        *max = *min = *start;
        return 0x80000000;
    }

    int* middle = start + (end - start) / 2;

    int maxLeft, minLeft;
    int leftDiff = MaxDiffCore(start, middle, &maxLeft, &minLeft);

    int maxRight, minRight;
    int rightDiff = MaxDiffCore(middle + 1, end, &maxRight, &minRight);

    int crossDiff = maxLeft - minRight;

    *max = (maxLeft > maxRight) ? maxLeft : maxRight;
    *min = (minLeft < minRight) ? minLeft : minRight;

    int maxDiff = (leftDiff > rightDiff) ? leftDiff : rightDiff;
    maxDiff = (maxDiff > crossDiff) ? maxDiff : crossDiff;
    return maxDiff;
}

在函数MaxDiffCore中,我们先得到第一个子数组中的最大的数对之差leftDiff,再得到第二个子数组中的最大数对之差rightDiff。接下来用第一个子数组的最大值减去第二个子数组的最小值得到crossDiff。这三者的最大值就是整个数组的最大数对之差。

目录
相关文章
|
存储 算法 程序员
【Leetcode 程序员面试金典 01.01】判定字符是否唯一 —— 位运算|哈希表
可以使用哈希表或位运算来解决此问题:由题可知s[i]仅包含小写字母,int[26]即能表示字符的出现次数;
|
算法 程序员 索引
【Leetcode 程序员面试金典 02.08】 —— 环路检测 |双指针
我们可以使用双指针解决本题,由数学推导可知:a 的距离为(环长度的倍数 - b),即 tmp 指针从头节点走到环开头节点等于 slow 指针走到环开头节点的距离
|
数据采集 数据挖掘 程序员
2024年Python最全资深程序员:学Python我推荐你用这几款编辑器,2024年最新面试考哪些
2024年Python最全资深程序员:学Python我推荐你用这几款编辑器,2024年最新面试考哪些
2024年Python最全资深程序员:学Python我推荐你用这几款编辑器,2024年最新面试考哪些
|
算法 前端开发 JavaScript
2024年Python最全资深程序员对于Python各个方向的面试经验分享,非常给力!,2024年最新2024金三银四面试季
2024年Python最全资深程序员对于Python各个方向的面试经验分享,非常给力!,2024年最新2024金三银四面试季
|
Java 程序员
Java this关键字详解(3种用法),Java程序员面试必备的知识点
Java this关键字详解(3种用法),Java程序员面试必备的知识点
|
算法 程序员 Go
PHP 程序员学会了 Go 语言就能唬住面试官吗?
【9月更文挑战第8天】学会Go语言可提升PHP程序员的面试印象,但不足以 solely “唬住” 面试官。学习新语言能展现学习能力、拓宽技术视野,并增加就业机会。然而,实际项目经验、深入理解语言特性和综合能力更为关键。全面展示这些方面才能真正提升面试成功率。
136 10
|
JavaScript 前端开发 小程序
CoderGuide 程序员前后端面试题库,打造全网最高质量题库
CoderGuide涵盖范围包括且不限于:前端面试题(Vue,React,JS,HTTP,HTML,CSS面试题等),后端面试题(Java,Python,Golang,PHP,Linux,Mysql面试题等),以及算法面试题,大厂面试题,高频面试题,校招面试题等,你想要的,这里都有!
248 2
|
前端开发 JavaScript 程序员
2024年最新65% 的程序员竟都是自学成才?_为啥学技术都自学,2024年最新42岁程序员面试
2024年最新65% 的程序员竟都是自学成才?_为啥学技术都自学,2024年最新42岁程序员面试
2024年最新65% 的程序员竟都是自学成才?_为啥学技术都自学,2024年最新42岁程序员面试
|
前端开发 应用服务中间件 程序员
老程序员分享:Nginx相关面试题
老程序员分享:Nginx相关面试题
157 2
|
SQL JavaScript Java
java程序员面试题大全含答案(2018--2019)
java程序员面试题大全含答案(2018--2019)