57. 数对之差的最大值:4种方法详解与总结[maximum difference of array]
【本文链接】
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。
【代码】
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.
// /* #include "stdafx.h" // brute force void test_base(int *numbers, int length) void test_case1() void test_case2() void test_case3() void test_main() int _tmain(int argc, _TCHAR *argv[]) |
【方法2:分治法】
通常【蛮力法】不会是最好的解法,我们想办法减少减法的次数。
假设我们把数组以中间元素为分割点分成两个子数组,我们其实没有必要拿左边的子数组中较小的数字A去和右边的子数组中较大的数字B作减法。我们可以想象,数对之差的最大值只有可能是下面三种情况之一:
(1)A和B都在第一个子数组中,即第一个子数组中的数对之差的最大值;
(2)A和B都在第二个子数组中,即第二个子数组中数对之差的最大值;
(3)A在第一个子数组中,是第一个子数组的最大值;B在第二个子数组中,是第二个子数组的最小值。
那么这三个差值的最大者就是整个数组中数对之差的最大值。
在前面提到的三种情况中,得到第一个子数组的最大值和第二子数组的最小值不是一件难事,但如何得到两个子数组中的数对之差的最大值?这其实是原始问题的子问题,我们可以递归地解决。
【代码】
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 // get max of a b c // get max diff from [left,right] and pass out max/min value // get right max diff // get cross max diff // update whole array min and max value int maxDiff = max3(leftDiff, rightDiff, crossDiff); // divide and conquer |
在函数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中最大的连续子数组之和。
【代码】
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; ]; // maximum continuous sub-sequence sum // get maximum continuous sub-sequence sum |
【方法4:动态规划法】
既然我们可以把求最大的数对之差转换成求子数组的最大和,而子数组的最大和可以通过动态规划求解,那我们是不是可以通过动态规划直接求解呢?下面我们试着用动态规划法直接求数对之差的最大值。
我们定义diff[i]是以数组中第i个数字为减数的所有数对之差的最大值(0<=i<n)。
则有diff[i+1] = max(diff[i], maxi-array[i+1]),maxi表示数组array[0,…i]的最大值。
【代码】
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 if(maxDiff < maxi - numbers[i]) |
【总结】
【方法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]的更多相关文章
- MySQL服务器线程数的查看方法详解
本文实例讲述了MySQL服务器线程数的查看方法.分享给大家供大家参考,具体如下: mysql重启命令: ? 1 /etc/init.d/mysql restart MySQL服务器的线程数需要在一个合 ...
- 笔试算法题(26):顺时针打印矩阵 & 求数组中数对差的最大值
出题: 输入一个数字矩阵,要求从外向里顺时针打印每一个数字: 分析: 从外向里打印矩阵有多重方法实现,但最重要的是构建合适的状态机,这样才能控制多重不同的操作: 注意有四种打印模式(左右,上下,右左, ...
- 求数组的最小数、最大值,求一组数的平均数,sort函数详解,类数组转数组
求数组的最小值和最大值 //求数组当中最大值和最小值 var arr=[3,2,6,1,45,23,456,23,2,6,3,45,37,89,30]; //第一种方法 根据排序方法来求最大值和最小值 ...
- 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 ...
- Sql中的并(UNION)、交(INTERSECT)、差(minus)、除去(EXCEPT)详解
UNION 查询选修了180101号或180102号课程或二者都选修了的学生学号.课程号和成绩. (SELECT 学号, 课程号, 成绩 FROM 学习 WHERE 课程号='180101' ...
- java abs(绝对值) , max(最大值),min(最小值) 方法的应用
在写程序是,我们常常会计算一个数的绝对值,这时我们可以使用java里的方法来计算 public class Demo1{ public static void main(String [] args) ...
- Newtonsoft.Json C# Json序列化和反序列化工具的使用、类型方法大全 C# 算法题系列(二) 各位相加、整数反转、回文数、罗马数字转整数 C# 算法题系列(一) 两数之和、无重复字符的最长子串 DateTime Tips c#发送邮件,可发送多个附件 MVC图片上传详解
Newtonsoft.Json C# Json序列化和反序列化工具的使用.类型方法大全 Newtonsoft.Json Newtonsoft.Json 是.Net平台操作Json的工具,他的介绍就 ...
- 详解tomcat连接数和线程数
前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server.xm ...
- 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)
如约而至,Java 10 正式发布! 3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...
随机推荐
- codevs 1378选课 树形DP
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; ],tr[] ...
- 坑爹的BFC;块格式上下文
Formatting context(FC) Formatting context 是 W3C CSS2.1 规范中的一个概念.它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位 ...
- HTML5动画实例
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- mysql-函数FOUND_ROWS()
FOUND_ROWS() SELECT语句中经常可能用LIMIT限制返回行数.有时候可能想要知道如果没有LIMIT会返回多少行,但又不想再执行一次相同语句.那么,在SELECT查询中包含SQL_CAL ...
- C++ 11 线程的同步与互斥
这次写的线程的同步与互斥,不依赖于任何系统,完全使用了C++11标准的新特性来写的,就连线程函数都用了C++11标准的lambda表达式. /* * thread_test.cpp * * Copyr ...
- nmap常用命令
1) 获取远程主机的系统类型及开放端口 nmap -sS -P0 -sV -O <target> 这里的 < target > 可以是单一 IP, 或主机名,或域名,或子网 - ...
- display & visibility区别
http://www.cnblogs.com/zhangran/archive/2012/08/29/2662459.html 说明:在学习css的过程中由于其中包含太多的元素.属性等等,总有许多是自 ...
- jquery------捕获异常处理
web.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC ...
- Java初学(一)
一.初识Java 1.JVM:Java跨平台是基于JVM(Java虚拟机)的,JVM不是跨平台的,针对不同平台有对应的JVM软件 2.JRE:Java开发出来的软件如果要运行还需要在环境中安装JRE( ...
- javaweb学习总结(三十一)——国际化(i18n)
一.国际化开发概述 软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的.符合来访者阅读习惯的页面或数据. 国际化(internationaliz ...