題目描述:
給你一個整數數組 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
題目大意:
將原來的數組擴大爲原來的k倍形成一個新的數組,問新數組的最大字段和。
思路:
此題很容易讓人想到暴力,先形成新數組再對新數組調用最大字段和算法,其實複雜度還可以往下降,看到這道題我就想起了2019ACM山東省賽的C題名字貌似是Wandering Robot,這道題給我的感覺跟那道題很相似,都是分析一下“頭”,分析一下“尾”,中間過程不用詳細考究。
對於這道題來說,上來先看一下原數組所有元素之和是否大於0。
如果大於0直觀上則代表着k越大最後的字段和就越大,每一個週期都是可以使子段和增加的。此時最終的最大字段和就是中間k-2個週期的和,再加上第一個週期的尾和最後一個週期的頭(前提是加上要使結果更大);
如果小於0則直觀上則代表着k越大最後的子段和就越小,這個時候可以計算兩個週期的最大字段和(前提是k>=2),之所以計算兩個週期的,是因爲一個週期不足以代表最後的最大字段和。舉個例子,原數組爲{3,6,-50,-30,-20,1,5},原數組的最大子段和是3+6=9,而兩個週期合併後的數組爲{3,6,-50,-30,-20,1,5,3,6,-50,-30,-20,1,5},最大子段和爲1+5+3+6=15。
如果k=1即只有一個週期,直接返回原數組的最大子段和即可。
上AC代碼:
class Solution {
public:
int dp[200000];
int kConcatenationMaxSum(vector<int>& arr, int k) {
int len=arr.size();
int num=0;
int i;
int ans=-0x3f3f3f3f;
memset(dp,0,sizeof(dp));
for(i=0;i<len;i++)
{
if(i>0&&dp[i-1]>0)
{
dp[i]=max(dp[i-1]+arr[i],dp[i]);
}
else
{
dp[i]=max(dp[i],arr[i]);
}
if(dp[i]>ans)
{
ans=dp[i];
}
num+=arr[i];
}
if(k>1&&num>0)
{
int sum1=0;
int ans1=0;
int sum2=0;
int ans2=0;
for(i=len-1;i>=0;i--)
{
sum1+=arr[i];
if(sum1>ans1)
{
ans1=sum1;
}
}
for(i=0;i<len;i++)
{
sum2+=arr[i];
if(sum2>ans2)
{
ans2=sum2;
}
}
long long int res=(long long int)num*(k-2)+ans1+ans2;
return res%(1000000007);
}
else if(k>1)
{
for(i=len;i<2*len;i++)
{
arr.push_back(arr[i-len]);
if(i>0&&dp[i-1]>0)
{
dp[i]=max(dp[i-1]+arr[i],dp[i]);
}
else
{
dp[i]=max(dp[i],arr[i]);
}
if(dp[i]>ans)
{
ans=dp[i];
}
}
return ans;
}
else
{
return ans;
}
}
};