题解 | #数组分组#

数组分组

http://www.nowcoder.com/practice/9af744a3517440508dbeb297020aca86

输入的所有数的集合:nums

根据题意,尝试把nums分成两组g5和g3

s5为能被5整除的数字的集和,s3为能被3整除(不能被5整除)的数字的集合

left为nums中排除s5和s3数字的所有剩余数字

l5是left中,和s5一起分到g5的数字;类似的,l3是left中,和s3一起分到g3的数字.

根据上述定义,有:

nums = g5 + g3

g5 = s5 + l5, g3 = s3 + l3

当sum(g5)=sum(g3)时满足均等分组的可能

当sum(l5)=sum(nums)/2-sum(s5)时满足均等分组,所以我们尝试找满足左式的情况。

定义target := sum(nums)/2-sum(s5),target是一已知固定值。

不失一般性,假设初始时所有left中元素都在l5中,假如此时sum(l5)=target则返回true;否则,尝试将现有l5中一部分数字拿出来(因为sum(nums)一定,会自动放入l3中)看剩下的数字是不是等于target。

我们遍历g5来考虑拿出当前数字后,产生的sum(g5)会不会等于target,如果等于则返回true。 我们交替地使用两个set对象,s1保存考虑当前数字前,通过移除(或保留)g5元素所能够得到的sum(g5');s2保存根据s1移除(或保留)当前数字后能得到的sum(g5')。

在完成g5的遍历后,移除(或保留)任意g5中数字所产生的sum(g5')都被考虑到了,检查target是否存在即可确定能否均分原数组。

因为每遍历到一个新的数字,s1到s2处理的元素个数都翻倍了,所以时间复杂度为O(2^N),空间复杂度为O(2^N)

#include<vector>
#include<set>

using namespace std;

int main(){
    int n, sum=0, sum5=0, cur, count5=0, sum5g=0;
    vector<int> g5;
    cin >> n;
    g5.resize(n);
    while(n--){
        cin >> cur;
        if(!(cur%5))
            sum5+=cur;
        else if(cur%3){
            g5[count5++] = cur;
            sum5g+=cur;
        }
        sum+=cur;
    }
    if(sum%2){
        cout << "false";
    }
    else{
        g5.resize(count5);
        int target = (sum>>1)-sum5;
        if(sum5g == target){
            cout << "true";
            return 0;
        }
        set<int> *s1, *s2;
        s1 = new set<int>{sum5g};
        s2 = new set<int>;
        for(int i=0;i<g5.size();++i){
            *s2 = *s1;
            for(auto c:*s1)
                s2->insert(c-g5[i]);
            if(s2->find(target)!=s2->end()){
                cout << "true";
                delete s1;
                delete s2;
                return 0;
            }
            *s1 = *s2;
        }
        delete s1;
        delete s2;
        cout << "false";
    }
    return 0;
}
全部评论

相关推荐

蚂蚁 基架java (n+6)*16 签字费若干
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务