翻转子数组得到最大的数组值
数组值定义为所有相邻元素差值的绝对值之和
翻转任意连续的子数组一次,求可行的最大值
1. 暴力分析(超时)
翻转后子数组内部数组值不变,所以只需分析子数组的边界翻转后带来的损失和收益
遍历取最大值即可,注意分情况讨论
枚举所有左右边界
class Solution {
public:
int maxValueAfterReverse(vector<int> &nums) {
int res = 0;
int n = nums.size();
for(int i=0;i<n-1;i++)
res = res + abs(nums[i]-nums[i+1]);
int profit = 0;
int gain,loss;
int lbound,rbound,lchange,rchange;
lchange = nums[0];
for(int i=1;i<n-1;i++)//左边界去交换
{
rchange = nums[i];
rbound = nums[i+1];
gain = abs(lchange-rbound);
loss = abs(rchange-rbound);
profit = max(profit,gain-loss);
}
rchange = nums[n-1];//右边界去交换
for(int i=1;i<n-1;i++){
lchange = nums[i];
lbound = nums[i-1];
gain = abs(rchange-lbound);
loss = abs(lchange-lbound);
profit = max(profit,gain-loss);
}
for(int i=1;i<n-2;i++){
lbound = nums[i-1];
lchange = nums[i];
for(int j=i+1;j<n-1;j++){
rchange = nums[j];
rbound = nums[j+1];
loss = abs(lbound-lchange) + abs(rbound-rchange);
gain = abs(lbound-rchange) + abs(rbound-lchange);
profit = max(profit,gain-loss);
}
}
return res + profit;
}
};
2. 优化(数学规律)
通过1可以发现该题就是最大化增益的过程,即最大化如下profit
profit = abs(lbound-rchange) + abs(rbound-lchange) - abs(lbound-lchange) - abs(rbound-rchange);
下面将对应四个值,简化成A,B,C,D
也就是profit = abs(A-C) + abs(B-D)-abs(A-B)-abs(C-D)
下面就是找规律时间
讨论AC、BD的大小情况,再讨论AB、CD的大小情况去掉绝对值,将结果必然小于等于0的去掉
可以看出来这里总共有16种情况,最后总结数学规律
class Solution {
public:
int maxValueAfterReverse(vector<int> &nums) {
int n = nums.size();
int max_ = INT_MIN; int min_ = INT_MAX;
int res = abs(nums[0]-nums[1]);
int profit = 0;
for(int i=1;i<n-1;i++){
res = res + abs(nums[i]-nums[i+1]);//计算总数组值
profit = max(profit,abs(nums[0]-nums[i+1])-abs(nums[i+1]-nums[i])); //左边界用于交换
profit = max(profit,abs(nums[n-1]-nums[i-1])-abs(nums[i]-nums[i-1])); //右边界用于交换
}
for(int i=1;i<n;i++){
max_ = max(max_,min(nums[i-1],nums[i]));//相邻数的最小值,最大化利润要求该值最大值
min_ = min(min_,max(nums[i-1],nums[i]));//相邻数的最大值,最大化利润要求该值最小值
}
return res + max(profit,2*(max_-min_));
}
};
3. 最终优化
class Solution {
public:
int maxValueAfterReverse(vector<int> &nums) {
int n = nums.size();
int max_ = INT_MIN; int min_ = INT_MAX;
int res = 0;
int profit = 0;
for(int i=1;i<n;i++){
res = res + abs(nums[i]-nums[i-1]);//计算总数组值
profit = max(profit,abs(nums[0]-nums[i])-abs(nums[i]-nums[i-1])); //左边界用于交换
profit = max(profit,abs(nums[n-1]-nums[i-1])-abs(nums[i]-nums[i-1])); //右边界用于交换
max_ = max(max_,min(nums[i-1],nums[i]));//相邻数的最小值,最大化利润要求该值最大值
min_ = min(min_,max(nums[i-1],nums[i]));//相邻数的最大值,最大化利润要求该值最小值
}
return res + max(profit,2*(max_-min_));
}
};