Given a set of ranges S, and an overlapping range R, find the smallest subset in S that encompases R

前端 未结 4 1532
-上瘾入骨i
-上瘾入骨i 2021-02-06 06:48

The following is a practice interview question that was given to me by someone, and I\'m not sure what the best solution to this is:

Given a set of ranges

4条回答
  •  囚心锁ツ
    2021-02-06 07:16

    Your assignment intrigued me, so I wrote a C++ program that solves the problem by iterating through the ranges that overlap the left side of the target range, and recursively searches for the smallest number of ranges that covers the remaining (right side) of the target range.

    A significant optimization to this algorithm (not shown in this program) would be to, for each recursive level, use the range that overlaps the left side of the target range by the largest amount, and discarding from further consideration all ranges that overlap the left side by smaller amounts. By employing this rule, I believe there would be at most a single descent into the recursive call tree. Such an optimization would produce an algorithm having complexity O(n log(n)). (n to account for the depth of recursion, and log(n) to account for the binary search to find the range having the most overlap.)

    This program produces the following as output:

    { (3, 9) (9, 12) (11, 14) }
    


    Here is the program:

    #include   // for std::pair
    #include    // for std::vector
    #include  // for std::cout & std::endl
    
    typedef std::pair range;
    typedef std::vector rangelist;
    
    // function declarations
    rangelist findRanges (range targetRange, rangelist candidateRanges);
    void print (rangelist list);
    
    
    int main()
    {
        range target_range = { 3, 13 };
    
        rangelist candidate_ranges =
            { { 1, 4 }, { 30, 40 }, { 20, 91 }, { 8, 10 }, { 6, 7 }, { 3, 9 }, { 9, 12 }, { 11, 14 } };
    
        rangelist result = findRanges (target_range, candidate_ranges);
    
        print (result);
        return 0;
    }
    
    
    // Recursive function that returns the smallest subset of candidateRanges that
    // covers the given targetRange.
    // If there is no subset that covers the targetRange, then this function
    // returns an empty rangelist.
    //
    rangelist findRanges (range targetRange, rangelist candidateRanges)
    {
        rangelist::iterator it;
        rangelist smallest_list_so_far;
    
        for (it = candidateRanges.begin (); it != candidateRanges.end (); ++it) {
    
            // if this candidate range overlaps the beginning of the target range
            if (it->first <= targetRange.first && it->second >= targetRange.first) {
    
                // if this candidate range also overlaps the end of the target range
                if (it->second >= targetRange.second) {
    
                    // done with this level - return a list of ranges consisting only of
                    // this single candidate range
                    return { *it };
                }
                else {
                    // prepare new version of targetRange that excludes the subrange
                    // overlapped by the present range
                    range newTargetRange = { it->second + 1, targetRange.second };
    
                    // prepare new version of candidateRanges that excludes the present range
                    // from the list of ranges
                    rangelist newCandidateRanges;
                    rangelist::iterator it2;
                    // copy all ranges up to but not including the present range
                    for (it2 = candidateRanges.begin (); it2 != it; ++it2) {
                        newCandidateRanges.push_back (*it2);
                    }
                    // skip the present range
                    it2++;
                    // copy the remainder of ranges in the list
                    for (; it2 != candidateRanges.end(); ++it2) {
                            newCandidateRanges.push_back (*it2);
                    }
    
                    // recursive call to find the smallest list of ranges that cover the remainder
                    // of the target range not covered by the present range
                    rangelist subList = findRanges (newTargetRange, newCandidateRanges);
    
                    if (subList.size () == 0) {
                        // no solution includes the present range
                        continue;
                    }
                    else if (smallest_list_so_far.size () == 0 ||               // - first subList that covers the remainder of the target range
                             subList.size () < smallest_list_so_far.size ())    // - this subList is smaller than all previous ones checked
                    {
                        // add the present range to the subList, which represents a solution
                        // (though possibly not optimal yet) at the present level of recursion
                        subList.push_back (*it);
                        smallest_list_so_far = subList;
                    }
                }
            }
        }
        return smallest_list_so_far;
    }
    
    // print list of ranges
    void print (rangelist list)
    {
        rangelist::reverse_iterator rit;
        std::cout << "{ ";
        for (rit = list.rbegin (); rit != list.rend (); ++rit) {
            std::cout << "(" << rit->first << ", " << rit->second << ") ";
        }
        std::cout << "}" << std::endl;
    }
    

提交回复
热议问题