Leetcode算法学习日志-53 Maximum Subarray
来源:互联网 发布:私募公募 知乎 编辑:程序博客网 时间:2024/06/05 05:58
Leetcode 53 Maximum Subarray
题目原文
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [-2,1,-3,4,-1,2,1,-5,4]
, the contiguous subarray[4,-1,2,1]
has the largest sum =6
.
题意分析
题目要求找到数组中一个连续的子数组,它的和最大,输出这个最大的和。可以看出如果采用Brute Force,算法的复杂度应该为O(n^2)。
解法分析
本题我选择的编程语言是C++,本题解法主要有以下两个:
- Divide and Conquer(分治法)
- Dynamic Programming(动态规划)
Divede and Conquer
要在数组里找一个和最大的数组,自然想到把用分治法这个数组分成两个数组,分别找到其中和最大的子数组。本题将数组分为左右两个子数组后,原数组和最大子数组的位置有以下三种情况:
- 为左子数组的和最大数组
- 为右子数组的和最大数组
- 在左右数组分界处的子数组
需要判断上面三个子数组哪一个的和最大,输出最大和。C++代码如下:
class Solution {public: int maxSubArray(vector<int>& nums) { int n=nums.size(); int res=maxSub(0,n-1,nums); return res; }private: int maxSub(int left,int right,vector<int>& nums){ if(left==right) return nums[left]; int mid=(left+right)/2; int maxLeft=maxSub(left,mid,nums); int maxRight=maxSub(mid+1,right,nums); int lMaxNearMid=nums[mid]; int lTemp=nums[mid]; int rMaxNearMid=nums[mid+1]; int rTemp=nums[mid+1]; int i,j; for(i=mid-1;i>=left;i--){ lTemp=lTemp+nums[i]; if(lTemp>lMaxNearMid) lMaxNearMid=lTemp; } for(j=mid+2;j<=right;j++){ rTemp=rTemp+nums[j]; if(rTemp>rMaxNearMid) rMaxNearMid=rTemp; } if((maxLeft>=maxRight)&&(maxLeft>=(lMaxNearMid+rMaxNearMid))) return maxLeft; else if(maxRight>=(lMaxNearMid+rMaxNearMid)) return maxRight; else return lMaxNearMid+rMaxNearMid; }};由于mid=n/2位置是确定的,所以由这一点开始向左、右求最大和算法复杂度为O(n),所以整个算法的递归式为T(n)=2T(n/2)+O(n),O(n)为’合并‘两子列时的时间消耗,所以总的算法复杂度为O(nlogn)。其中将原数组分成两个子数组可以利用迭代器来完成,可以用如下代码定义生成左子数组left:
vector<int> left(nums.begin(),nums.begin()+nums.size()/2);
上述代码相当于指定了vector left的begin()和end()。
Dynamic Programming
动态规划方法常常用于求解最优化问题,和分治法相同的是,动态规划方法也是将原问题分解为许多字问题,通过组合子问题的解来求解原问题。而它们之间的不同点在于,分治法往往将问题分解为互不相交的子问题,而动态规划方法用于子问题有重叠的情况,也就是有相同子子问题,这时候利用分治的思想会反复求解同一个子问题,也就是那些公共子问题,而动态规划方法对每个子问题只求解一次,将其解存在数组(下标有序)或散列表(下标无序)中,避免了不必要的计算工作,这也同时要求问题满足最有子结构,也即问题的最优解是由相关子问题的最优解组合而成的。这也是典型的空间换时间的时空权衡例子。
动态规划方法主要有两种实现形式:
- 带备忘的自顶向下法
这种方法采用递归形式编写,但会保存每个子问题的解,通常用数组或散列表存储,当需要返回一个子问题的解时,首先检查是否已经保存过这个解,如果是,则直接返回,不是,则用通常方法计算这个解。
- 自底向上法
这种方法保证了在求解每一个子问题时,规模比他小的相关子问题都已经被求解,只需要通过数组或者散列表查询到所需子问题的值,而不需要递归调用。
目前看来,对于《算法导论》上的钢条切割问题,原问题即所选规模最大问题,不需要做相应变形;而本题需要将规模最大问题变形为找长度为n的序列的和最大数组,且最后一个元素包含在和最大数组中。对于钢条切割问题,最大规模问题的解就是我们最终要求的最优解,而对于本题,最大规模问题的解不一定是原问题的最优解,所以需要用一个值来动态存储目前的到的最优解。但他们的共同特点均是需要保存每个子问题的解,免于重复计算。
上述问题均是要求最优解的值,如果需要得到最优解本身,则需要在执行过程中维护一些额外的信息。以下是C++代码:
class Solution {public: int maxSubArray(vector<int>& nums) { int n=nums.size(); int *DP=new int[n]; DP[0]=nums[0]; int i; int maxA=DP[0]; for(i=1;i<n;i++){ DP[i]=(DP[i-1]>0)?DP[i-1]+nums[i]:nums[i]; maxA=max(maxA,DP[i]); } return maxA; }};代码中用DP[n]存储每个子问题的最优解,用maxA动态保存目前为止产生的最优解的值。由于只有一个循环,所以算法复杂度为O(n)。
- Leetcode算法学习日志-53 Maximum Subarray
- Leetcode算法学习日志-152 Maximum Product Subarray
- Leetcode算法学习日志-718 Maximum Length of Repeated Subarray
- LeetCode 53: Maximum Subarray
- LeetCode(53)Maximum Subarray
- [leetcode 53] Maximum Subarray
- leetcode-53 Maximum Subarray
- leetcode || 53、Maximum Subarray
- leetcode[53]-Maximum Subarray
- LeetCode---(53)Maximum Subarray
- leetcode 53: Maximum Subarray
- leetcode-53-Maximum Subarray
- Leetcode#53 Maximum Subarray
- LeetCode(53) Maximum Subarray
- Leetcode#53||Maximum Subarray
- leetcode 53 Maximum Subarray
- LeetCode 53: Maximum Subarray
- leetcode[53]Maximum Subarray
- 环形有序链表插入节点
- django时间的时区问题(转)
- Shell下的进度条
- 求两个集合的交集和并集
- spring mybatis mapper接口注解方式注入
- Leetcode算法学习日志-53 Maximum Subarray
- java代码读取到excel的两列数据,进行相乘得到新的数据
- sql 编辑功能名称重复性校验
- 电解电容器的用途
- c++ 继承/派生、访问属性、构造函数
- D. Nested Segments
- 从集成方法到神经网络:自动驾驶技术中的机器学习算法有哪些?
- 三分钟学会用SpringMVC搭建最小系统(超详细)
- RocketMQ原理解析-producer 4.发送分布式事物消息