`
SunnyYoona
  • 浏览: 366885 次
社区版块
存档分类
最新评论

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

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
分享到:
评论

相关推荐

    C/C++笔试题(附答案,华为面试题系列)

    高调度效率和限制资源使用的好处,线程池中的线程达到最大数时,其他线程就会排队 等候。 15函数模板与类模板有什么区别? 答:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化 必须由...

    java 面试题 总结

    最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。 Hashtable和HashMap采用的hash/rehash算法都大概...

    c++ 面试题 总结

    C++面试题 1.是不是一个父类写了一个virtual 函数,如果子类覆盖它的函数不加virtual ,也能实现多态? virtual修饰符会被隐形继承的。 private 也被集成,只事派生类没有访问权限而已 virtual可加可不加 子类的...

    超级有影响力霸气的Java面试题大全文档

    超级有影响力的Java面试题大全文档 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。...

    最新笔试面试常用算法收集打包

    2009/09/27 15:06 1,444,591 c+c++程序员面试宝典.CHM 2009/09/27 15:08 76,288 linux试题.doc 2009/09/30 14:16 3,084 QQ 2009.txt 2009/09/28 17:15 77,312 Trie树.doc 2009/09/28 17:14 49,664 使用正向最大匹配...

    net学习笔记及其他代码应用

    net的最近面试经典试题ASP.NET面试题集合 1. 简述 private、 protected、 public、 internal 修饰符的访问权限。 答 . private : 私有成员, 在类的内部才可以访问。 protected : 保护成员,该类内部和继承类中...

    C#开发实例大全(基础卷).软件开发技术联盟(带详细书签) PDF 下载

    实例032 递归算法的经典面试题 39 实例033 制作一个数字猜猜看小游戏 40 实例034 使用goto语句在数组中搜索指定图书 42 第3章 字符串处理技术 44 3.1 字符及字符串转换 45 实例035 将字母全部转换为大写或小写 45 ...

Global site tag (gtag.js) - Google Analytics