2.14 求数组的子数组之和的最大值
2.14 求数组的子数组之和的最大值
基本问题:一个有N个正整数元素的一维数组,这个数组有很多子数组,那么子数组之和的最大值是什呢吗?
解法:
解法 : 动态规划
动态规划
状态定义 : dp[i] 表示包含第i个元素的最大子序和
状态转移方程:dp[i] = max{dp[i-1] + arr[i] , arr[i]}
初始状态:dp[0] = nums[0];
拓展问题:
- 1 如果数组[A[0], ...,A[n-1]]首尾相连,题目又该如何解释?
- 2 如果题目要求同时返回最大子数组的位置,算法应该如何改变?还能保持\(O(n)\)的时间复杂度么?
all coding
// 2.14 求数组的子数组之和的最大值
class Test{
public static void main(String[] args) {
/**
基本问题:一个有N个正整数元素的一维数组,这个数组有很多子数组,那么子数组之和的最大值是什呢吗?
解法:
解法 : 动态规划
*/
int[] arr = new int[]{1,-2,3,5,-3,2};
print(arr);
System.out.println(maxSubArray2(arr));
print(maxSubArrayPos(arr));
}
public static void print(int[] arr){
for(int i:arr) System.out.print(i+" ");
System.out.println();
}
/**
动态规划
状态定义
dp[i] 表示包含第i个元素的最大子序和
状态转移方程
dp[i] = max{dp[i-1] + arr[i] , arr[i]}
初始状态:
dp[0] = nums[0];
*/
public static int maxSubArray(int[] nums) {
if(nums==null || nums.length==0) return 0;
int[] dp = new int[nums.length];
dp[0] = nums[0];
for(int i = 1;i <nums.length;i++){
dp[i] = Math.max(dp[i-1]+nums[i],nums[i]);
}
int res = Integer.MIN_VALUE;
for(int num:dp) res = Math.max(num,res);
return res;
}
/**
拓展问题:
1 如果数组[A[0], ...,A[n-1]]首尾相连,题目又该如何解释?
2 如果题目要求同时返回最大子数组的位置,算法应该如何改变?还能保持$O(n)$的时间复杂度么?
*/
/**
拓展问题1:
*/
public static int maxSubArray2(int[] nums) {
if(nums==null || nums.length==0) return 0;
int[] dp = new int[nums.length*2];
dp[0] = nums[0];
for(int i = 1;i <nums.length*2;i++){
dp[i] = Math.max(dp[i-1]+nums[i%nums.length],nums[i%nums.length]);
}
int res = Integer.MIN_VALUE;
for(int num:dp) res = Math.max(num,res);
return res;
}
/**
拓展问题2:
return [start,end]
*/
public static int[] maxSubArrayPos(int[] nums){
int[] dp = new int[nums.length];
dp[0] = nums[0];
for(int i = 1;i <nums.length;i++){
dp[i] = Math.max(dp[i-1]+nums[i],nums[i]);
}
int max = Integer.MIN_VALUE;
for(int num:dp) max = Math.max(max,num);
int[] res = new int[2];
for(int i = 0;i<dp.length;i++) if(dp[i] == max) res[1] = i;
int start;
for(start= res[1];max!=0;start--) max-=nums[start];
res[0] = start-1;
return res;
}
}
Saying Less Doing More