思路:
题目的主要信息:
- 给一串数组,每次找到一个位置进行一次操作:将该位置前后一个数及本身改为三者中的最大值
- 一共进行n次操作,每次操作需要找到改变后使数组和最大那个位置来改变
方法一:暴力解法(超时)
具体做法:
利用二进制掩码的特性,枚举所有位置选择或是不选择的组合(相当于n次操作,选择的位置进行排列足组合),按照顺序模拟改变的值,最后更新较大值即可。
class Solution {
public:
vector<int> solve(int n, vector<int>& a) {
vector<int> res(n, 0);
for(int i = 1; i < (1 << n); i++){ //枚举数字的可能性
int num = 0;
vector<int> temp = a; //每次记录修改的数组
for(int j = 0; j < n; j++){
if((i >> j) & 1){
num++;
int maxnum = a[j];
//处理边界
if(j - 1 >= 0)
maxnum = max(maxnum, temp[j - 1]);
if(j + 1 < n)
maxnum = max(maxnum, temp[j + 1]);
if(j - 1 >= 0)
temp[j - 1] = maxnum;
if(j + 1 < n)
temp[j + 1] = maxnum;
temp[j] = maxnum;
}
}
int sum = 0;
for(int j = 0; j < n; j++) //求和
sum += temp[j];
res[num - 1] = max(res[num - 1], sum);//更新
}
return res;
}
};复杂度分析:
- 时间复杂度:
,两个循环,外循环掩码自然是
,内循环一次遍历
- 空间复杂度:
,使用辅助数组temp每次回归原来的数组,res属于必要空间
方法二:动态规划
具体做法:
要求的最大值等于数组a的元素和加上每次操作后增加最多的大小。因此我们可以一开始就求出数组a的元素和,然后用辅助数组dp,代表每次操作
位置后,
处的值为
时对应的最大总增量。
我们再借助队列做一个类似bfs的遍历,队列中记录的分别是元素下标、第几次操作、以当前元素为中的连续三个最大值。对于每次操作,从队列中取出元素,向后扩展,更新最大值。
我们设置两个dp,其中dp如图所示是记录每次操作后的值,初始时如图所示初始化。而dp1是用来在bfs时找到当前操作的最大增加量,最后需要更新进dp中,dp1的更新方式类似的dp,就不画图了。
class Solution {
public:
struct S{
int pos, k, mx; //pos是下标,k是第几次操作,mx当前连续三个的最大值
};
vector<int> solve(int n, vector<int>& a) {
vector<int> res(n, INT_MIN);
int maxe = *max_element(a.begin(), a.end()); //找到最大值
//dp[i][j]代表每次操作i位置后,i处的值为j时对应的最大总增量
vector<vector<int> > dp(n + 1, vector<int>(maxe + 1, -1));
vector<vector<int> > dp1 = dp; //备份在这里供还原dp时使用
queue<S> q;
int sum = 0;
for(int i = 0; i < n; i++){ //处理连续三个数
sum += a[i];
int mx = a[i], g = a[i], cnt = 1;
if(i > 0){ //非下界
mx = max(a[i - 1], mx);
g += a[i - 1]; //这三个总值
cnt++; //这三个的元素个数,边界处没有三个
}
if(i < n - 1){ //非上界
mx = max(a[i + 1], mx);
g += a[i + 1];
cnt++;
}
q.push(S{i, 1, mx}); //放入队列中方便bfs
dp[i][mx] = max(dp[i][mx], cnt * mx - g); //更新增量最大
res[0] = max(cnt * mx - g, res[0]);
}
for(int k = 1; k < n; k++){ //n次操作
int sz = q.size();
for(int i = 0; i < sz; i++){ //遍历找到最大增加量
auto s = q.front(); //出队列
q.pop();
int pos = s.pos, kk = s.k, mx = s.mx;
for(int j = pos + 1; j < n; j++){ //向后扩展mx
int mx2, g, cnt = 2;
if(j == pos + 1) { //左边
mx2 = mx;
g = 2 * mx;
}
else if(j == pos + 2) {
mx2 = max(mx, a[j]);
g = mx + a[j];
}
else {
mx2 = max(a[j - 1], a[j]);
g = a[j - 1] + a[j];
}
if(j < n - 1){ //右边
mx2 = max(a[j + 1], mx2);
g += a[j + 1];
cnt++;
}
if(dp1[j][mx2] == -1)
q.push({j, kk + 1, mx2});//保存状态
dp1[j][mx2] = max(dp1[j][mx2], cnt * mx2 - g + dp[pos][mx]);//更新结果
res[kk] = max(dp1[j][mx2], res[kk]);
}
dp[pos][mx] = -1;//还原数组为-1,方便下一轮扩展用
}
swap(dp, dp1);
}
for(int i = 0; i < n; i++)
res[i] += sum;
return res;
}
};
复杂度分析:
- 时间复杂度:
,最坏情况为n次操作,每次相当于遍历dp矩阵
- 空间复杂度:
,最大空间为矩阵的空间

京公网安备 11010502036488号