题目来源
题目描述
你有一个整数数组 nums。你只能将一个元素 nums[i] 替换为 nums[i] * nums[i]。
返回替换后的最大子数组和。
示例 1:
输入:nums = [2,-1,-4,-3]
输出:17
解释:你可以把-4替换为16(-4*(-4)),使nums = [2,-1,16,-3]. 现在,最大子数组和为 2 + -1 + 16 = 17.
示例 2:
输入:nums = [1,-1,1,1,-1,-1,1]
输出:4
解释:你可以把第一个-1替换为1,使 nums = [1,1,1,1,-1,-1,1]. 现在,最大子数组和为 1 + 1 + 1 + 1 = 4.
实现:
class Solution {
public:
int maximumSum(vector<int>& arr){
}
};
题目解析
状态表示:操作即nums[i]替换为nums[i] * nums[i]
- f(i, 0):以第i个数字为结尾,没有使用操作,最大子数组和
- f(i, 1):以第i个数字结尾,已经使用操作,最大子数组和
状态转移:
- 以第i个数字结尾,一次都没有操作,说明前i-1个数字也没有使用操作,所以由f(i - 1, 0)转移
- 以第i个数字结尾,使用了操作,则有两种转移方式:
- 前i-1个数字没有使用操作,但是第i个数字使用了操作,所以由f(i - 1, 0)转移
- 前i-1个数字已经使用操作,所以由f(i - 1, 1)转移
小贪心,使用了操作肯定比没使用操作的状态大,所以最后汇总只需要在使用了的状态里取最大值
class Solution {
struct Info{
int noOperator; // 不进行任何操作
int replaceOne; // 无论如何替换一次(可以替换i,或者替换i之前的数)
};
public:
int maximumSum(vector<int>& nums){
int len = nums.size();
std::vector<Info> dp(len);
dp[0].noOperator = nums[0]; // 不进行任何操作,以nums[i]结尾, 能够得到的最大子数组和
dp[0].replaceOne = nums[0] * nums[0]; // 此时,只能替换nums[0]
int max = dp[0].replaceOne;
for (int i = 1; i < len; ++i) {
dp[i].noOperator = std::max( // 不进行任何操作:
nums[i], // 要么只要当前
nums[i] + dp[i - 1].noOperator // 要么当前和之前联合
);
dp[i].replaceOne = std::max( // 替换一次:
nums[i] * nums[i] + dp[i - 1].noOperator, // 替换当前 + 之前不替换
nums[i] + dp[i - 1].replaceOne // 不替换当前 + 替换之前
) ;
max = std::max(max, dp[i].replaceOne);
}
return max;
}
};