805. 陣列的均值分割
阿新 • • 發佈:2018-11-11
題目
給定的整數陣列 A ,我們要將 A陣列 中的每個元素移動到 B陣列 或者 C陣列中。(B陣列和C陣列在開始的時候都為空)
返回true ,當且僅當在我們的完成這樣的移動後,可使得B陣列的平均值和C陣列的平均值相等,並且B陣列和C陣列都不為空。
示例:
輸入:
[1,2,3,4,5,6,7,8]
輸出: true
解釋: 我們可以將陣列分割為 [1,4,5,8] 和 [2,3,6,7], 他們的平均值都是4.5。
注意:
A 陣列的長度範圍為 [1, 30].
A[i] 的資料範圍為 [0, 10000].
思路
這個問題是個np問題(n!),但是,由資料可以進行一定的處理,減少執行時間。
直接的暴力搜尋顯然是不可行的,O(30!)絕對會超時。
首先考慮到,若A集合若能分為B,C兩個,那麼B,C必然有一個集合元素較少,少於等於A集合元素的一半,那麼我們處理時的遞迴深度就變成最多15,也即O(15!),但是,直接跑這個演算法也是會超時的。
除此之外,我們還可以考慮剔除重複的遞迴狀態,也就是和,當前處理下標,遞迴深度這三個變數完全一樣的情況。
最後,即便做到以上兩點,還是會TL,參考了一下別人的程式碼,發現還可以處理最大深度,這需要一個簡單的性質
如果 平均數*遞迴深度 不是整數,那麼我們是不可能在這個深度找到解的。
那麼,我們就可以運用這個性質減少最大遞迴深度,最後終於過了。由此可見,處理明顯的Np問題時,要想在限時內完成,主要要考慮通過題目減少n值還有剔除冗餘狀態。
程式碼
class Solution {
public:
bool splitArraySameAverage(vector<int>& vec) {
if(vec.size() <= 1){
return false;
}
maxDepth = vec.size() / 2;
sum = 0;
sort(vec.begin() , vec.end() );
for(int loop = 0 ; loop < vec.size() ; loop++){
sum += vec[loop];
}
arraySize = vec.size() ;
unordered_map <int , bool>mp[15][30];
while( sum * maxDepth % arraySize != 0) {
maxDepth --;
}
return findArray(0 , 0 , vec , 1 , mp );
}
bool findArray(int nowSum , int nowIndex , vector<int>&vec , int depth
, unordered_map <int , bool> mp[][30] ){
if(nowIndex >= arraySize){
return false;
}
if(mp[depth - 1][nowIndex].count(nowSum) ){
return false;
}
else{
mp[depth - 1][nowIndex][nowSum] = true;
}
for(int loop = nowIndex ; loop < arraySize ; loop++){
int nextSum = nowSum + vec[loop] ;
if( nextSum * arraySize == sum * depth ){
return true;
}
else if( depth < maxDepth && loop < arraySize
&& findArray(nextSum , loop + 1 , vec , depth + 1 , mp ) ){
return true;
}
}
return false;
}
private:
int sum;
int arraySize ;
int maxDepth;
};