由于數據范圍是2*10^5所以必然是遍歷一次,子數組必定要用到前綴和,之前的題目中總是遇到的是子數組的和能不能被k整除,而這里不一樣的是子數組的長度能不能被k整除,如果單純的枚舉長度必定超時,而看看題解得出的思路,我在做之前的題目中也有類似的。
首先,我們要想判斷一個長度能不能被k整除,實際上就是判斷 (j-i)%k==0 ,也就是說 j%k=i%k 同余定理,而求子數組的最大元素和,實際上就是求sum[j]-sum[i],那么我們如何找這個符合條件的i呢,我們只需要讓sum[i]盡可能的小,sum[j]盡可能的大,在滿足這兩個條件的情況下,實際上就是讓我們求:sum[j]-sum[j%k(i)]的最大值sum[j]它是可以在枚舉的過程中不斷更新的,而我們需要確定的是j%k也就是i的最小值。
我們可以用一個最小值數組來保存每遇到一個j,它取模后的值(也就是i)的最小值
這樣我們就能在枚舉的過程中不斷的更新sum[i]的最小值,從而求出子數組和的最大值。
下面是求與j同余的i的最小值的方法
int i =j%k;minn[i]=min(minn[i],sum[j]);
下面是通過代碼:
class Solution {
public:long long sum[200005];
long long minn[200005];long long maxSubarraySum(vector<int>& nums, int k) {for(int i=0;i<k;i++){minn[i]=LLONG_MAX/2;}minn[0]=0;for(int i=0;i<nums.size();i++){sum[i+1]=sum[i]+nums[i];}//我們要想判斷一個長度能不能被k整除//實際上就是判斷 (j-i)%k==0 //也就是說 j%k=i%k 同余定理//而求子數組的最大元素和//實際上就是求sum[j]-sum[i]//那么我們如何找這個符合條件的i呢//我們可以在//我們只需要讓sum[i]盡可能的小//sum[j]盡可能的大//不斷更新結果long long ans=LLONG_MIN;for(int j=1;j<=nums.size();j++){int i=j%k;ans=max(ans,sum[j]-minn[i]);minn[i]=min(minn[i],sum[j]);} return ans;}
};
要注意的是minn[i]初始化為LLONG_MAX/2,因為在減的過程中如果初始化為LLONG_MAX,那么相減的值可能是一個正數,而不是負數了,這樣在 ans=max(ans,sum[j]-minn[i]);就會更新到錯誤的答案,我之前沒有加出錯了,所以必須加上。還有一點要注意如果j%k==0,也就是i=0,那么它初始化的最小值應該為0,也就是minn[0]=0;而不是LLONG_MAX/2;
時間復雜度O(n)。