1. 程式人生 > >805. 陣列的均值分割

805. 陣列的均值分割

題目

給定的整數陣列 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; };