本文涉及知识点
C++动态规划
LeetCode1911. 最大子序列交替和
一个下标从 0 开始的数组的 交替和 定义为 偶数 下标处元素之 和 减去 奇数 下标处元素之 和 。
比方说,数组 [4,2,5,3] 的交替和为 (4 + 5) - (2 + 3) = 4 。
给你一个数组 nums ,请你返回 nums 中任意子序列的 最大交替和 (子序列的下标 重新 从 0 开始编号)。
一个数组的 子序列 是从原数组中删除一些元素后(也可能一个也不删除)剩余元素不改变顺序组成的数组。比方说,[2,7,4] 是 [4,2,3,7,2,1,4] 的一个子序列(加粗元素),但是 [2,4,2] 不是。
示例 1:
输入:nums = [4,2,5,3]
输出:7
解释:最优子序列为 [4,2,5] ,交替和为 (4 + 5) - 2 = 7 。
示例 2:
输入:nums = [5,6,7,8]
输出:8
解释:最优子序列为 [8] ,交替和为 8 。
示例 3:
输入:nums = [6,2,1,2,4,5]
输出:10
解释:最优子序列为 [6,1,5] ,交替和为 (6 + 5) - 1 = 10 。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 105
动态规划
动态规划的状态表示
dp[i][j]表示nums[0…i]中长度%2==j的子序列的最大交替和。空间复杂度:O(n)
动态规划的转移方程
枚举前置状态:
dp[i+1] =dp[i] ,不选择nums[i+1]
sign = (0==j) ? 1 : -1
MaxSelf(dp[i+1][(j+1)%2],dp[i][j]+sign*nums[i+1])
单个状态转移的时间复杂度:O(1) 总时间复杂度:O(n)
动态规划的填报顺序
i = 0 To n-1 j =0 to 1
动态规划的初始值
dp[0][0]=0,dp[0][1] = nums[0] 其它全为 LLONG_MIN/10。
动态规划的返回值
dp.back的最大值
代码
核心代码
class Solution {
public:
long long maxAlternatingSum(vector<int>& nums) {
const int N = nums.size();
vector<vector<long long>> dp(N, vector<long long>(2,LLONG_MIN/2));
dp[0][0] = 0;
dp[0][1] = nums[0];
for (int i = 0; i + 1 < N; i++) {
dp[i + 1] = dp[i];
for (int j = 0; j < 2; j++) {
dp[i + 1][(j+1)%2] = max(dp[i + 1][(j + 1) % 2], dp[i][j] +((j?-1:1)* nums[i+1]));
}
}
return *max_element(dp.back().begin(), dp.back().end());
}
};
单元测试
vector<int> nums;
TEST_METHOD(TestMethod11)
{
nums = { 4,2,5,3 };
auto res = Solution().maxAlternatingSum(nums);
AssertEx(7LL, res);
}
TEST_METHOD(TestMethod12)
{
nums = { 5,6,7,8 };
auto res = Solution().maxAlternatingSum(nums);
AssertEx(8LL, res);
}
TEST_METHOD(TestMethod13)
{
nums = { 6,2,1,2,4,5 };
auto res = Solution().maxAlternatingSum(nums);
AssertEx(10LL, res);
}