【本文链接】

http://www.cnblogs.com/hellogiser/p/maximum-difference-of-array.html

题目】

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

分析

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

有如下4种方法对此题进行解答。


方法1:蛮力法

很容易想到,让每一个数字逐个减去它右边的所有数字,并通过比较得到数对之差的最大值。所有的数对只差共有n*(n-1)/2,因而时间复杂度为O(n^2)。我们设定只有1个数字时,最大数对之差为INT_MIN,即0x80000000。

【代码】

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
 
// 57_MaxDiffOfArray.cpp : Defines the entry point for the console application.
//

/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/5/24
*/

#include "stdafx.h"
#include <iostream>
using namespace std;

// brute force
int MaxDiff_BruteForce(int *numbers, int length)
{
    // O(n^2)
)
        return INT_MIN;
    //init maxdiff to min value
    int maxDiff = INT_MIN;
    ; i < length; ++i)
    {
        ; j < length; ++j)
        {
            int diff = numbers[i] - numbers[j];
            // update maxDiff
            if (diff > maxDiff)
                maxDiff = diff;
        }
    }
    return maxDiff;
}

void test_base(int *numbers, int length)
{
    cout << MaxDiff_BruteForce(numbers, length) << endl;
}

void test_case1()
{
    };
    int length = sizeof(a) / sizeof(int);
    test_base(a, length);
}

void test_case2()
{
    };
    int length = sizeof(a) / sizeof(int);
    test_base(a, length);
}

void test_case3()
{
    };
    int length = sizeof(a) / sizeof(int);
    test_base(a, length);
}

void test_main()
{
    test_case1();
    test_case2();
    test_case3();
}

int _tmain(int argc, _TCHAR *argv[])
{
    test_main();
    ;
}
/*
-2147483648
-2
11
*/


方法2:分治法

通常【蛮力法】不会是最好的解法,我们想办法减少减法的次数。

假设我们把数组以中间元素为分割点分成两个子数组,我们其实没有必要拿左边的子数组中较小的数字A去和右边的子数组中较大的数字B作减法。我们可以想象,数对之差的最大值只有可能是下面三种情况之一:

(1)A和B都在第一个子数组中,即第一个子数组中的数对之差的最大值;

(2)A和B都在第二个子数组中,即第二个子数组中数对之差的最大值;

(3)A在第一个子数组中,是第一个子数组的最大值;B在第二个子数组中,是第二个子数组的最小值。

那么这三个差值的最大者就是整个数组中数对之差的最大值。

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

【代码】

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/5/24
*/

#define MIN(a,b) a<b?a:b
#define MAX(a,b) a>b?a:b

// get max of a b c
int max3(int a, int b, int c)
{
    int t = a > b ? a : b;
    return t > c ? t : c;
}

// get max diff from [left,right] and pass out max/min value
int MaxDiffCore(int *left, int *right, int *min, int *max)
{
    if(left == right)
    {
        *max = *min = *left;
        return INT_MIN;
    }
    ;
    // get left max diff
    int minLeft, maxLeft;
    int leftDiff = MaxDiffCore(left, middle, &minLeft, &maxLeft);

// get right max diff
    int minRight, maxRight;
    , right, &minRight, &maxRight);

// get cross max diff
    int crossDiff = maxLeft - minRight;

// update whole array min and max value
    *min = MIN(minLeft, minRight);
    *max = MAX(maxLeft, maxRight);

int maxDiff = max3(leftDiff, rightDiff, crossDiff);
    return maxDiff;
}

// divide and conquer
int MaxDiff_DivideAndConquer(int *numbers, int length)
{
    // T(n)=2*T(n/2)+O(1)===>Tn=O(n)
)
        return INT_MIN;
    int min, max;
    , &min, &max);
}

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


方法3:转化法

转换为求子数组的最大和问题。

接下来再介绍一种比较巧妙的解法。如果输入一个长度为n的数组numbers,我们先构建一个长度为n-1的辅助数组diff,并且diff[i]等于numbers[i]-numbers[i+1](0<=i<n-1)。如果我们从数组diff中的第i个数字一直累加到第j个数字(j > i),也就是diff[i] + diff[i+1] + … + diff[j] = (numbers[i]-numbers[i+1]) + (numbers[i + 1]-numbers[i+2]) + ... + (numbers[j] – numbers[j + 1]) = numbers[i] – numbers[j + 1]。

分析到这里,我们发现原始数组中最大的数对之差(即numbers[i] – numbers[j + 1])其实是辅助数组diff中最大的连续子数组之和。

【代码】

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/5/24
*/
// max sub sequence sum
int MaxSubSequenceSum(int *array, int length)
{
    // f = max(f+a[i],a[i])
)
        return INT_MIN;

];
    ];
    ; i < length; i++)
    {
        )
            f = array[i];
        else
            f += array[i];
        // update greatest
        if (greatest < f)
            greatest = f;
    }
    return greatest;
}

// maximum continuous sub-sequence sum
int MaxDiff_Transformation(int *numbers, int length)
{
    // Tn=O(n)
)
        return INT_MIN;
    // generate diff array
;
    int *diff = new int[diffLength];
    ; i < diffLength; ++i)
        diff[i] = numbers[i] - numbers[i + ];

// get maximum continuous sub-sequence sum
    int maxDiff = MaxSubSequenceSum(diff, diffLength);
    delete []diff;
    return maxDiff;
}

方法4:动态规划法

既然我们可以把求最大的数对之差转换成求子数组的最大和,而子数组的最大和可以通过动态规划求解,那我们是不是可以通过动态规划直接求解呢?下面我们试着用动态规划法直接求数对之差的最大值。

我们定义diff[i]是以数组中第i个数字为减数的所有数对之差的最大值(0<=i<n)。

则有diff[i+1] = max(diff[i], maxi-array[i+1]),maxi表示数组array[0,…i]的最大值。

【代码】

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/5/24
*/

// max diff using dynamic programming
// diff[i]: maxDiff ending at array[i] (0<=i<n)
// maxi: max value of array[0,...i]
// diff[i+1] = max (diff[i],maxi-array[i+1])
int MaxDiff_DP(int *numbers, int length)
{
    // Tn=O(n)
)
        return INT_MIN;
    ];
    int maxDiff = INT_MIN;
    ; i < length; i++)
    {
        ])
            maxi = numbers[i - ];

if(maxDiff < maxi - numbers[i])
            maxDiff = maxi - numbers[i];
    }
    return maxDiff;
}


【总结】

方法1:蛮力法】时间复杂度为O(n2),空间复杂度为O(1)。

方法2:分治法】时间复杂度为O(n),空间复杂度为O(1)。 由于该方法基于递归实现,因此会有额外的时间、空间消耗。

方法3:转化法】时间复杂度为O(n),空间复杂度为O(n)。

方法4:动态规划法】时间复杂度为O(n),空间复杂度为O(1)。该方法则没有额外的时间、空间消耗,并且它的代码是最简洁的,因此这是最值得推荐的一种解法。

【参考】

http://zhedahht.blog.163.com/blog/static/2541117420116135376632/

http://www.cnblogs.com/python27/archive/2011/12/01/2270724.html

【本文链接】

http://www.cnblogs.com/hellogiser/p/maximum-difference-of-array.html

57. 数对之差的最大值:4种方法详解与总结[maximum difference of array]的更多相关文章

  1. MySQL服务器线程数的查看方法详解

    本文实例讲述了MySQL服务器线程数的查看方法.分享给大家供大家参考,具体如下: mysql重启命令: ? 1 /etc/init.d/mysql restart MySQL服务器的线程数需要在一个合 ...

  2. 笔试算法题(26):顺时针打印矩阵 & 求数组中数对差的最大值

    出题: 输入一个数字矩阵,要求从外向里顺时针打印每一个数字: 分析: 从外向里打印矩阵有多重方法实现,但最重要的是构建合适的状态机,这样才能控制多重不同的操作: 注意有四种打印模式(左右,上下,右左, ...

  3. 求数组的最小数、最大值,求一组数的平均数,sort函数详解,类数组转数组

    求数组的最小值和最大值 //求数组当中最大值和最小值 var arr=[3,2,6,1,45,23,456,23,2,6,3,45,37,89,30]; //第一种方法 根据排序方法来求最大值和最小值 ...

  4. Codeforces Round #283 (Div. 2) A. Minimum Difficulty【一个数组定义困难值是两个相邻元素之间差的最大值。 给一个数组,可以去掉任意一个元素,问剩余数列的困难值的最小值是多少】

    A. Minimum Difficulty time limit per test 2 seconds memory limit per test 256 megabytes input standa ...

  5. Sql中的并(UNION)、交(INTERSECT)、差(minus)、除去(EXCEPT)详解

    UNION 查询选修了180101号或180102号课程或二者都选修了的学生学号.课程号和成绩. (SELECT  学号, 课程号, 成绩 FROM   学习 WHERE   课程号='180101' ...

  6. java abs(绝对值) , max(最大值),min(最小值) 方法的应用

    在写程序是,我们常常会计算一个数的绝对值,这时我们可以使用java里的方法来计算 public class Demo1{ public static void main(String [] args) ...

  7. Newtonsoft.Json C# Json序列化和反序列化工具的使用、类型方法大全 C# 算法题系列(二) 各位相加、整数反转、回文数、罗马数字转整数 C# 算法题系列(一) 两数之和、无重复字符的最长子串 DateTime Tips c#发送邮件,可发送多个附件 MVC图片上传详解

    Newtonsoft.Json C# Json序列化和反序列化工具的使用.类型方法大全   Newtonsoft.Json Newtonsoft.Json 是.Net平台操作Json的工具,他的介绍就 ...

  8. 详解tomcat连接数和线程数

    前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server.xm ...

  9. 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)

    如约而至,Java 10 正式发布!   3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...

随机推荐

  1. ES6 你可能不知道的事 – 基础篇

    序 ES6,或许应该叫 ES2015(2015 年 6 月正式发布),对于大多数前端同学都不陌生. 首先这篇文章不是工具书,不会去过多谈概念,而是想聊聊关于每个特性 你可能不知道的事,希望能为各位同学 ...

  2. 【HDU 5578】Friendship of Frog

    题 题意 求相同字母最近距离 分析 用数组保存各个字母最后出现的位置,维护最小距离. 代码 #include <cstdio> int c[30],n,p,a,minl; char ch; ...

  3. 【HDU 2203】亲和串

    题 题意 给你一个字符串s1,字符串s2,s1循环移位,使s2包含在s1中,则s2 是s1的亲和串 分析 把s1自身复制一遍接在后面. 方法一: 用strstr函数. 方法二: KMP算法. 方法三: ...

  4. 洛谷P2726 阶乘 Factorials

    题目背景 N的阶乘写作N!,表示小于等于N的所有正整数的乘积. 题目描述 阶乘会变大得很快,如13!就必须用32位整数类型来存储,到了70!即使用浮点数也存不下了. 你的任务是找到阶乘最前面的非零位. ...

  5. 关于IntentFilter的几点注意事项:

    http://blog.csdn.net/cnnumen/article/details/8464786 IntentFilter就是用于描述intent的各种属性, 比如action, catego ...

  6. Android Studio集成SVN报错:can't use subversion command line client : svn

    Android Studio集成SVN插件,check out出代码后,每次开启都会在右上角出现如下错误: Can't use Subversion command line client: svn ...

  7. Initialization of deep networks

    Initialization of deep networks 24 Feb 2015Gustav Larsson As we all know, the solution to a non-conv ...

  8. mysql 索引 详解

    索引是快速搜索的关键.MySQL索引的建立对于MySQL的高效运行是很重要的.下面介绍几种常见的MySQL索引类型. 在数据库表中,对字段建立索引可以大大提高查询速度.假如我们创建了一个 mytabl ...

  9. angular2怎么使用第三方的库(jquery等)

    网上找了很多教材都搜索不到该部分类型,自己测试了下写了该教程. 场景说明:项目需要使用bootstrap,众所周知bootstrap没有时间日期控件的,需要使用第三方控件,我对如何在angular2中 ...

  10. Jquery 获取URL参数

    使用jquery获取url以及使用jquery获取url参数是我们经常要用到的操作 1.jquery获取url很简单,代码如下 1.window.location.href; 其实只是用到了javas ...