目录
1、最大子数组和
1.1 算法原理
- 状态表示dp[i]:
以i位置为结尾,最长子序列之和
- 状态转移方程:
dp[i]=max(dp[i-1]+nums[i-1],nums[i-1]);
- 初始化:
int[] dp = new int[n+1];
dp[0]=0;
- 填表顺序:
从左往右
- 返回值:
dp中最大序列和
1.2 算法代码
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int[] dp = new int[n + 1];
// 初始化
dp[0] = 0;
int ret = Integer.MIN_VALUE;
// 填表
for(int i = 1; i <= n; i++) {
dp[i] = Math.max(dp[i - 1] + nums[i - 1], nums[i - 1]);
ret = Math.max(ret, dp[i]);
}
return ret;
}
}
2、环形子数组的最大和
2.1 算法原理
核心:将带环问题转化为普通不带环问题
- 状态表示:
f[i]:以i位置为结尾,最大子序列之和
g[i]:以i位置为结尾,最小子序列之和
- 状态转移方程:
f[i] = Math.max(f[i - 1] + nums[i - 1], nums[i - 1]);
g[i] = Math.min(g[i - 1] + nums[i - 1], nums[i - 1]);
- 初始化:
下标映射:dp[i]-->nums[i-1]
虚拟节点:要保证后续填表的正确性:f[0]=g[0]=0;
- 填表顺序:
从左往右,两个表一起填。
- 返回值(特殊情况:当表中的数都是负数时(都在最小子序列中),此时sum-gMin=0):
找到f表中的最大值 fMax;
找到g表中的最小值 gMin,进而得到最大和序列:sum-gMin;
return sum == gMin ? fMax : max(fMax, sum-gMin);
2.2 算法代码
class Solution {
public int maxSubarraySumCircular(int[] nums) {
int n = nums.length;
int sum = 0;
for(int x : nums) sum += x;
int[] f = new int[n + 1];//内部最大子数组
int[] g = new int[n + 1];//内部最小子数组
f[0] = g[0] = 0;
int fMax = Integer.MIN_VALUE;
int gMin = Integer.MAX_VALUE;
for(int i = 1; i <= n; i++) {
f[i] = Math.max(f[i - 1] + nums[i - 1], nums[i - 1]);
g[i] = Math.min(g[i - 1] + nums[i - 1], nums[i - 1]);
fMax = Math.max(fMax, f[i]);
gMin = Math.min(gMin, g[i]);
}
// 注意数组中全是负数的情况
return sum == gMin ? fMax : Math.max(fMax, sum - gMin);
}
}