题目一:给定一个数组,求该数组的最大子数组和【与求最长连续子数组互为姊妹题】
题目二:给定一个数组,求该数组的最大两个子数组的和(子数组位置无重合)
解题一:
- 技巧法:声明两个临时变量res和cur,res保存访问到当前元素所得的最大和,cur保存每次加上当前元素的和(注意:当cur小于0时,更新为0)
- 动态规划法
// 子数组的最大和[技巧法]
func getMaxSum(arr []int) int {
if len(arr) == 0 {
return IntMin
}
res := IntMin
cur := 0
for _, ele := range arr {
cur += ele
if cur > res {
res = cur
}
if cur < 0 {
cur = 0
}
}
return res
}
// 子数组最大和[动态规划法]
// dp[i]表示到num[i]的最大和,dp[i] = max(arr[i], arr[i]+dp[i-1])
func getMaxSum2(arr []int) int {
if len(arr) == 0 {
return 0
}
dp := make([]int, len(arr))
dp[0] = arr[0]
for i := 1; i < len(arr); i++ {
tmpSum := arr[i] + dp[i-1]
if tmpSum > arr[i] {
dp[i] = tmpSum
} else {
dp[i] = arr[i]
}
}
res := dp[0]
for _, ele := range dp {
if ele > res {
res = ele
}
}
return res
}
解题二:在上面题目思路的基础上,求两个子数组的最大和,可以考虑将原数组num划分为两部分left和right,即以当前元素为分界线(当前元素指第二个元素到倒数第二个元素),左边最大和与右边最大和,整个过程访问完毕即求得最大和。代码如下:
int subArrayMaxSum2(int[] num){
if(num == null || num.length < 2)
return 0;
int[] right = new int[num.length];
right[num.length-1] = num[num.length-1];
int cur = num[num.length-1];
for(int i=num.length-2; i>=0; i--){
cur = Math.max(cur, 0);
cur += num[i];
right[i] = Math.max(right[i+1], cur);
}
int res = num[0] + right[1];
int lMaxSum = num[0];
cur = num[0];
for(int i=1; i<num.length-1; i++){//右边最少一个元素
cur += num[i];
lMaxSum = Math.max(lMaxSum, cur);
res = Math.max(res, lMaxSum + right[i+1]);
}
return res;
}