题目描述
给你一个整数数组 arr 和一个整数 k。
首先,我们要对该数组进行修改,即把原数组 arr 重复 k 次。
举个例子,如果 arr = [1, 2] 且 k = 3,那么修改后的数组就是 [1, 2, 1, 2, 1, 2]。
然后,请你返回修改后的数组中的最大的子数组之和。
注意,子数组长度可以是 0,在这种情况下它的总和也是 0。
由于 结果可能会很大,所以需要 模(mod) 10^9 + 7 后再返回。
示例 1:
输入:arr = [1,2], k = 3
输出:9
示例 2:
输入:arr = [1,-2,1], k = 5
输出:2
示例 3:
输入:arr = [-1,-2], k = 7
输出:0
提示:
1 <= arr.length <= 10^5
1 <= k <= 10^5
-10^4 <= arr[i] <= 10^4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/k-concatenation-maximum-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
初步分析
首先讲一下如何求一个任意元素数组的最大和连续子串
这个问题在《算法导论》看到过,对于一个数组我们设它的左端点是l,右端点是r,中点为k=(l+r)/2.那么这个最大和连续子串的位置最多只有3种情况,即在(l,k),(k+1,r),还有就是横跨中点的子串。所以对于前面两种情况我们用递归,对于横跨中点的最大子串我们可以直接遍历在线性时间里求得最大值。所以对于任何一个数组求它最大和连续子串的复杂度就是T(n)=2*T(n/2)+O(n).所以由递归树或者主定理可知T(n)=O(nlogn)
那对这道题是不是直接构造一个重复k次的数组然后这样做就行了呢?说实话我最开始居然就是这么想的,后来TLE了。我果然还是太单纯(菜)了。
因为
1 <= arr.length <= 10^5
1 <= k <= 10^5
所以这个数组有可能会变得很大很大如果是用数组的话会爆栈。但如果是用vector的话又会超时。所以不得不想想其他方法。毕竟这个数组是有周期性的性质我们根本没用到。
解题步骤
首先还是可以写一个O(nlogn)的最大连续子串和的函数g()
然后int k1=一次重复的最大值(用g()做)
如果(k>=2)int k2=两次重复的最大值(用g()做)
对于k=1,2的时候很简单。就直接输出k1,k2就行了。
当k>=3时
我们int sum=原本数组的和
if(sum>0)
return max(k1,k2+(k-2)*sum);//要么就不跨数组就k1,如果跨了的话那往中间一直塞sum则是最大
else
return max(k1,k2);//要么就不跨数组就k1,如果跨了的话那往中间塞sum就会变小,所以就k1和k2比较
//这里大家想一想是不是这样的,这个跨的意思就是占用了几个重复的子串。
注意要用long long存和哦。还要记得取模哦。
上代码
class Solution {
public:
const long long mod=1000000007;
long long recursive_max(vector<int>& arr,int l, int r){
if(l==r) return arr[l];
int k=(l+r)/2;
long long max_mid=arr[k];
long long max_left=0,sum_left=0;
for(int i=k-1;i>=l;--i){
sum_left+=arr[i];
max_left=max(max_left,sum_left);
}
long long max_right=0,sum_right=0;
for(int i=k+1;i<=r;++i){
sum_right+=arr[i];
max_right=max(max_right,sum_right);
}
max_mid+=max_left;
max_mid+=max_right;
long long result_left=recursive_max(arr,l,k);
long long result_right=recursive_max(arr,k+1,r);
long long result=0;
result= result_left>result ? result_left : result;
result=result_right>result ? result_right : result;
result= max_mid > result ? max_mid : result;
return result;
}
int kConcatenationMaxSum(vector<int>& arr, int k) {
long long sum=0;
for(int j=0;j<arr.size();++j){
sum+=arr[j];
}
//如果k==1
long long k1=recursive_max(arr,0,arr.size()-1)%mod;
if(k==1) return k1%mod;
//如果k==2
int len=arr.size();
for(int j=0;j<len;++j){
arr.push_back(arr[j]);
}
long long k2=recursive_max(arr,0,arr.size()-1)%mod;
if(k==2) return max(k1,k2)%mod;
//如果k>=3
if(sum>0){
return max(k1,k2+(k-2)*sum)%mod;
}
else{
return max(k1,k2)%mod;
}
}
};