Given a set S, find all the maximal subsets whose sum <= k

后端 未结 6 1444
感动是毒
感动是毒 2021-02-14 21:52

This is a Facebook interview question I came across at an online portal.

Given a set S, find all the maximal subsets whose sum <= k. For example, if S = {1, 2, 3, 4,

6条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2021-02-14 21:56

    I know it's late to answer, but I think I've found a simple solution for this problem. We enumerate subsets of S in lexicographical order using backtracking and check the sum of subset generated so far.

    When the sum exceeds k, the interesting part comes: we need to check if the generated subset is a proper subset of previously reported items.

    One solution is to keep all the reported subsets and check for inclusion, but it's wasteful.

    Instead, we calculate the difference between the k and the sum. If there is an element e in S such that e not in subset and e <= (k - sum), then the set we generated is a proper subset of a previously reported subset, and we can safely skip it.

    Here is the complete working program in plain old C++, demonstrating the idea:

    #include 
    #include 
    #include 
    #include 
    
    typedef std::set Set;
    typedef std::vector SubSet;
    
    bool seen_before(const Set &universe, const SubSet &subset, int diff) {
        Set::const_iterator i = std::mismatch(universe.begin(), universe.end(),
                                              subset.begin()).first;
        return i != universe.end() && *i <= diff;
    }
    
    void process(const SubSet &subset) {
        if (subset.empty()) {
            std::cout << "{}\n";
            return;
        }
        std::cout << "{" << subset.front();
        for (SubSet::const_iterator i = subset.begin() + 1, e = subset.end();
             i != e; ++i) {
            std::cout << ", " << *i;
        }
        std::cout << "}\n";
    }
    
    void generate_max_subsets_rec(const Set &universe, SubSet &subset,
                                  long sum, long k) {
        Set::const_iterator i = subset.empty()
            ? universe.begin()
            : universe.upper_bound(subset.back()),
            e = universe.end();
        if (i == e) {
            if (!seen_before(universe, subset, k - sum))
                process(subset);
            return;
        }
        for (; i != e; ++i) {
            long new_sum = sum + *i;
            if (new_sum > k) {
                if (!seen_before(universe, subset, int(k - sum)))
                    process(subset);
                return;
            } else {
                subset.push_back(*i);
                if (new_sum == k)
                    process(subset);
                else
                    generate_max_subsets_rec(universe, subset, new_sum, k);
                subset.pop_back();
            }
        }
    }
    
    void generate_max_subsets(const Set &universe, long k) {
        SubSet subset;
        subset.reserve(universe.size());
        generate_max_subsets_rec(universe, subset, 0, k);
    }
    
    int main() {
        int items[] = {1, 2, 3, 4, 5};
        Set u(items, items + (sizeof items / sizeof items[0]));
        generate_max_subsets(u, 7);
        return 0;
    }
    

    The output is all maximum subsets in lexicographical order, one per line:

    {1, 2, 3}
    {1, 2, 4}
    {1, 5}
    {2, 5}
    {3, 4}
    

提交回复
热议问题