[程序员面试题精选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。这三者的最大值就是整个数组的最大数对之差。

目录
相关文章
|
3月前
|
存储 算法 程序员
【Leetcode 程序员面试金典 01.01】判定字符是否唯一 —— 位运算|哈希表
可以使用哈希表或位运算来解决此问题:由题可知s[i]仅包含小写字母,int[26]即能表示字符的出现次数;
|
3月前
|
算法 程序员 索引
【Leetcode 程序员面试金典 02.08】 —— 环路检测 |双指针
我们可以使用双指针解决本题,由数学推导可知:a 的距离为(环长度的倍数 - b),即 tmp 指针从头节点走到环开头节点等于 slow 指针走到环开头节点的距离
|
3月前
|
Java 程序员
【Leetcode 程序员面试金典 05.01】插入 —— 位运算
位运算问题,只需要把 N 的 i 到 j 位都置 0 后再和 M 左移 i 位的结果进行按位或即可
|
3月前
|
NoSQL Java MongoDB
程序员的50大MongoDB面试问题及答案
程序员的50大MongoDB面试问题及答案
|
3月前
|
网络协议 Linux 程序员
程序员的50大Linux面试问题及答案(二)
程序员的50大Linux面试问题及答案(二)
|
3月前
|
Java 应用服务中间件 程序员
程序员的20大JSP面试问题及答案
程序员的20大JSP面试问题及答案
|
3月前
|
消息中间件 存储 Kafka
程序员的27大Kafka面试问题及答案
程序员的27大Kafka面试问题及答案
|
3月前
|
存储 网络协议 Java
程序员的23大IO&NIO面试问题及答案
程序员的23大IO&NIO面试问题及答案
|
3月前
|
算法 架构师 安全
10年Java面试总结:Java程序员面试必备的面试技巧
作为一名资深10年Java技术专家,我参与了无数次的面试,无论是作为面试者还是面试官。在这里,我将分享我的一些面试经历和面试技巧,希望能帮助即将面临面试的Java程序员们。回顾我的Java职业生涯,我清晰地记得一次特别的面试经历。那是我申请一家知名科技公司的Java开发岗位。为了这次面试,我花了几周的时间准备,这不仅包括Java的基础和高级知识,还有关于公司产品的研究。
143 0
|
2月前
|
运维 算法 程序员
程序员去国企:长城资产IT岗位秋招面试记录
【2月更文挑战第7天】本文介绍2024届秋招中,中国长城资产管理股份有限公司的信息技术岗岗位一面的面试基本情况、提问问题等~