在O(N)时间内求解 正数数组中 两个数相加的 最大值

简介:

一,问题描述

给定一个正数数组arr(即数组元素全是正数),找出该数组中,两个元素相加的最大值,其中被加数的下标大于加数的下标。由加法运算的可逆性,j >i 这个条件可以去掉。

即求出: maxValue = max{arr[j]+arr[i] and j > i} 

在数组arr中没有重复的元素情况下,若被加数的下标可以等于加数的下标,则该问题变成了寻找正数数组arr中最大值的元素了。因为 max{arr[i]} + max{arr[i]} 一定比 max{arr[i]} + arr[j] 大,其中arr[j]为数组中的任意某个元素。

而《数据结构与算法分析 Java语言描述》Mark Allen Weiss著 书中第37页 2.28 题中并没有指出数组arr中的元素不通重复。

 

二,求解思路

有两种思路,一种是对数组中的每个元素,求出该元素与它后面元素的和,然后记录下最大的。

如,对于下标为 i 的元素,for each j belongs to [i+1, arr.length)需要求出 sum=arr[i]+arr[j] 其中,i belongs to [0,arr.length) and j >=i

这算法的时间复杂度为O(N^2)

第二种思路是,先将加数初始化为下标为0的那个元素(arr[i]=arr[0]),然后,j 往后扫描,若遇到比arr[i]大的元素,则下标 i=j。也就是说,i 总是记录比当前arr[i]更大的元素(贪心思想

更详细的解释,类似于这篇文章

代码如下:

复制代码
 1     //O(N). find out the max sum of two numbers in a positive array
 2     public static int maxSum(int[] arr){
 3         int i = 0;
 4         int max = 0;//数组中所有的元素都是正数
 5         int addValue;
 6         for(int j = 1; j < arr.length; j++){
 7             addValue = arr[i] + arr[j];
 8             if(addValue > max)
 9                 max = addValue;
10             if(arr[j] - arr[i] > 0)
11                 i = j;//记录更大的arr[i]
12         }
13         return max;
14     }
复制代码

 

三,运行时间的比较

采用 这篇文章 中提到的随机数生成算法 来随机生成一个数组,然后比较上面两个算法的运行时间。

机器环境如下:

OS:win7 64bit、RAM:6GB、CPU:Pentium(R)Dual-Core E5800@3.2GHz

时间比较如下:

数组大小        maxSum运行时间(O(N))       maxSum2算法2运行时间(O(N^2))

100*100             1                                        27

200*100             1                                        68

300*100             2                                        133

500*100             3                                        359

 

此外,按照同样的思路,也可以求解两个数相加的最小值了,哈哈。。。。

求两数相加的最小值,也同样是每次贪心,贪一个较arr[i]更小的值即可,这简直和求解两数相减的最大值一模一样!!!

代码如下:

复制代码
 1     public static int minSum(int[] arr){
 2         int min = Integer.MAX_VALUE;
 3         int i = 0;
 4         int addValue;
 5         for(int j = 1; j < arr.length; j++){
 6             addValue = arr[j] + arr[i];
 7             if(addValue < min)
 8                 min = addValue;
 9             if(arr[j] - arr[i] < 0)
10                 i = j;
11         }
12         return min;
13     }
复制代码

 

再扩展一下:还可以计算三个数相加的最大值。还是同样的思路,当碰到比上一次运算中的 加数 更大的数时,则把该数替换掉原来加数中最小的那个加数。(三数相加,视为有三个加数。。。^-^)

再扩展一下,是不是感觉到这个问题和 求解最大子序列和 有点联系了?  二者都是直接跳过某些不需要“关注”的元素,并总是“贪心”出 下一个候选元素。

 

完整代码如下:

复制代码
 1 public class MaxSum {
 2     
 3     //O(N). find out the max sum of two numbers in a positive array
 4     public static int maxSum(int[] arr){
 5         int i = 0;
 6         int max = 0;//数组中所有的元素都是正数
 7         int addValue;
 8         for(int j = 1; j < arr.length; j++){
 9             addValue = arr[i] + arr[j];
10             if(addValue > max)
11                 max = addValue;
12             if(arr[j] - arr[i] > 0)
13                 i = j;//记录更大的arr[i]
14         }
15         return max;
16     }
17     
18     
19     public static int maxSum2(int[] arr){
20         int max = 0;
21         int addValue;
22         for(int i = 0; i < arr.length; i++){
23             for(int j = i+1; j < arr.length; j++){
24                 addValue = arr[j] + arr[i];
25                 if(addValue > max)
26                     max = addValue;
27             }
28         }
29         return max;
30     }
31     
32     public static void main(String[] args) {
33         int[] arr = C2_2_8.algorithm3(100*100*10);
34 
35         long start = System.currentTimeMillis();
36         int r = maxSum(arr);
37         long end = System.currentTimeMillis();
38         System.out.println("maxValue=" + r + "  O(N)'s time:" + (end -start));
39         
40         long start2 = System.currentTimeMillis();
41         int r2 = maxSum2(arr);
42         long end2 = System.currentTimeMillis();
43         System.out.println("maxValue=" + r2 + "  O(N^2)'s time:" + (end2 - start2));
44     }
45 }
复制代码
相关文章
|
小程序
关于微信小程序过滤器filter的正确使用
关于微信小程序过滤器filter的正确使用
|
弹性计算 固态存储 大数据
阿里云服务器CPU处理器Intel Xeon(Cascade Lake) Platinum 8269CY
阿里云服务器ECS实例CPU处理器Intel Xeon(Cascade Lake) Platinum 8269CY
1571 0
 阿里云服务器CPU处理器Intel Xeon(Cascade Lake) Platinum 8269CY
|
缓存 NoSQL Redis
【浅谈电商】如何防止重复下单
首先我们要知道什么时候是下单操作。以JD为例: 购物车 -> 结算页面 -> 下单页面 - 购物车:购物车 - 结算页面:此页面可以查看待支付金额,使用的优惠券,填写地址,运费等等。 - 下单页面:此页面可以选择结算方式,并且页面展示付款倒计时,也就是说订单已经创建完成。 在下单页面时,由于用户点击下单按钮多次、或者重试策略导致在订单服务中接收到了`两次同样`的下单请求。
877 0
【浅谈电商】如何防止重复下单
|
云安全 人工智能 Cloud Native
关于阿里云aca和acp哪个好?阿里云认证证书有含金量吗?
由于网络的变迁,为网络行业的兴起提供了很好的发展。在其中出现了更多的新职位,从而为许多人创造了更大的就业机会,与此同时也增加了就业竞争。 那么接下来跟随着认证大使的小编一起了解下关于阿里云aca和acp哪个好?
2487 0
关于阿里云aca和acp哪个好?阿里云认证证书有含金量吗?
|
域名解析 负载均衡
如何选择阿里云服务器固定带宽更加节省费用,个人小经验分享
在购买阿里云服务器时,通常要设定服务器带宽。为了保证服务器带宽的稳定,一般选择固定带宽,如1Mbps、3Mbps、10Mbps或20Mbps。但固定带宽往往不好选择,高了浪费,低了可能会影响高峰时间性能。那么如何选择阿里云服务器固定带宽更加节省费用呢,以下是小编的个人小经验分享给大家。
1211 0
如何选择阿里云服务器固定带宽更加节省费用,个人小经验分享
|
机器学习/深度学习 人工智能 编解码
AI运动:阿里体育端智能最佳实践
过去一年,阿里体育技术团队在端智能方面不断探索,特别在运动健康场景下实现了实践落地和业务赋能,这就是AI运动项目。AI运动项目践行运动数字化的理念,为运动人口的上翻提供了重要支撑,迈出了阿里体育端智能运动领域的第一步,为用户带来了更加有趣的新颖玩法。上线以来,项目受到了广泛关注。
AI运动:阿里体育端智能最佳实践
|
数据可视化 程序员 项目管理
强大、好用、适合程序员/软件开发者的专业编辑器/笔记软件综合评测和全面推荐
Atom、EMACS、Vim 、Notepad++、Sublime Text、Brackets、Vim、Visual Studio Code、Eclipse、PSPAD、GEANY、JEDIT、NETBEANS、Nvu、NoteTab、Gedit…
677 0
强大、好用、适合程序员/软件开发者的专业编辑器/笔记软件综合评测和全面推荐
|
机器学习/深度学习 人工智能 自然语言处理
万物皆Contrastive Learning,从ICLR和NIPS上解读对比学习最新研究进展(一)
万物皆Contrastive Learning,从ICLR和NIPS上解读对比学习最新研究进展(一)
1519 0
万物皆Contrastive Learning,从ICLR和NIPS上解读对比学习最新研究进展(一)
|
机器学习/深度学习 数据采集 自然语言处理
淘宝Push智能文案生成
Push是淘宝重要促活手段之一,运营同学通过投放各类营销、产品Push以达到唤端、促活目的。Push素材通常由人群、商品或者活动、文案构成,与用户有直接沟通的便是Push文案,优质的素材文案吸引用户点击起到正向促活作用,而劣质内容不仅可能影响用户体验,更甚者可能引发用户关闭通道。
1621 0
淘宝Push智能文案生成