简体   繁体   中英

Merge Overlapping intervals C++ problem solving

The question is from InterviewBit(coding website):

Given a collection of intervals, merge all overlapping intervals. For example:

Given: [1,3],[2,6],[8,10],[15,18]

return: [1,6],[8,10],[15,18].

Make sure the returned intervals are sorted.

I hope my logic is correct, but I get errors in the code. Maybe because I've not used the vectors properly? My code is:

vector<Interval> Solution::merge(vector<Interval> &A) {
    // Do not write main() function.
    // Do not read input, instead use the arguments to the function.
    // Do not print the output, instead return values as specified
    // Still have a doubt. Checkout www.interviewbit.com/pages/sample_codes/ for more details
    vector<int> mergedIntervals;
    if(A.size()==0){
        return A;
    }
    sort(A.begin(),A.end());
    //temp vector to store first ele 
    vector<int> tempInterval=A[0];
    
    //merge operation
    for(auto it: A){
        if(it[0]<tempInterval[1]){
            tempInterval[1]=max(it[1],tempInterval[1]);
        }
        else{
            mergedIntervals.push_back(tempInterval);
            tempInterval=it;
        }
        mergedIntervals.push_back(tempInterval);
        return mergedIntervals;
    }
    
}
/**
 * Definition for an interval.
 * struct Interval {
 *     int start;
 *     int end;
 *     Interval() : start(0), end(0) {}
 *     Interval(int s, int e) : start(s), end(e) {}
 * };
 */

Error:

Compiling your Code...
> Error!
solution.cpp: In member function 'std::vector<Interval> Solution::merge(std::vector<Interval>&)':

solution.cpp:21:33: error: conversion from '__gnu_cxx::__alloc_traits<std::allocator<Interval>, Interval>::value_type' {aka 'Interval'} to non-scalar type 'std::vector<int>' requested

   25 |     vector<int> tempInterval=A[0];

      |                                 ^

solution.cpp:25:14: error: no match for 'operator[]' (operand types are 'Interval' and 'int')

   29 |         if(it[0]<tempInterval[1]){

      |              ^

solution.cpp:26:35: error: no match for 'operator[]' (operand types are 'Interval' and 'int')

   30 |             tempInterval[1]=max(it[1],tempInterval[1]);

      |  

                             ^

and so on..

You can do quite a bit better:

At first, accept the vector by value – this creates a copy right on the start:

vector<Interval> Solution::merge(vector<Interval> data)
// (note the dropped ampersand!)

Then you can merge the intervals within this copy in place ! For the case that you should not be allowed to or otherwise be prevented from that modification (no access to the header used for the tests) then you can (and only then you should) simply create a copy of the argument and continue with that one:

vector<Interval> Solution::merge(vector<Interval>& source)
{
    std::vector data(source); // just create a copy as very first step
                              // and continue operating on this...
    // ...

You still need to sort, but I assume you didn't provide a custom operator< for the Interval class anyway (and I would't do so either because requirements might change pretty much depending on the specific use case), so you might provide the appropriate comparator explicitly:

std::sort
(
    data.begin(), data.end(),
    [](Interval const& x, Interval const& y)
    {
        return x.begin < y.begin;
    }
);

Finally you can now merge, as mentioned, in place, by only retaining the merged elements (similar as std::remove / std::remove_if do):

auto cur = data.begin();
for(auto i = cur; i != data.end(); ++i)  // you could start with cur + 1, too, but
                                         // that would require special handling
                                         // for the empty vector... 
{
    if(i->begin <= cur->end)
    {
        // intervals overlap (or touch) -> need to merge!
        cur->end = std::max(cur->end, i->end); // enlarges the interval, if need be
    }
    else
    {
        // no overlap any more, need to start a new interval
        // -> copy current towards front (note: there might be a gap
        //    due to already merged intervals!)
        *++cur = std::move(*i);
        // (moving is always correct, but not necessary HERE as identical to
        // copying anyway – I recommend still adding it by principle to get
        // used to when re-using the pattern elsewhere)
    }
}

Now cur points to the last element to be retained, we need yet to remove // the surplus ones (this is called the erase-remove-idiom ):

data.erase(++cur, data.end()); // note: need to increment to point BEHIND
                               // the last element to be retained!

All you yet need to do is return the vector received that way ;)

Final notes:

  • This is entirely untested code – if you find a bug, please fix yourself.
  • This code assumes the intervals already being normalised (as your original version does as well) – if you cannot expect this as pre-condition you might want to add code to fix (swapping begin and end members if the latter smaller than the former).

When I change vector<int> to Interval I get this:

#include <vector>
#include <algorithm>
using namespace std; // this is bad but all the stupid sites open std

struct Interval {
     int start;
     int end;
     Interval() : start(0), end(0) {}
     Interval(int s, int e) : start(s), end(e) {}
};

vector<Interval> merge(vector<Interval> &A) {
    // Do not write main() function.
    // Do not read input, instead use the arguments to the function.
    // Do not print the output, instead return values as specified
    // Still have a doubt. Checkout www.interviewbit.com/pages/sample_codes/ for more details
    vector<Interval> mergedIntervals;
    if (A.size()==0){
        return A;
    }
    sort(A.begin(), A.end(),
         [](const Interval &lhs, const Interval &rhs) {
            return lhs.start < rhs.start;
        });
    //temp vector to store first ele 
    Interval tempInterval=A[0];
    
    //merge operation
    for (const auto &it: A){
        if (it.start<tempInterval.end) {
            tempInterval.end=max(it.end,tempInterval.end);
        } else {
            mergedIntervals.push_back(tempInterval);
            tempInterval=it;
        }
        mergedIntervals.push_back(tempInterval);
    }
    return mergedIntervals;    
}

The only tricky bit is that Interval lacks operator< so you have to provide a comparison for sort .

You can improve that by reserving space in mergedIntervals or even better do it in-place in A and trim A to fit.

And obviously you should never ever ever ever ever ever ever write a function signature like that. Use:

vector<Interval> merge(const vector<Interval> &A);
vector<Interval> merge(vector<Interval> &&A);
void merge_in_place(vector<Interval> &A);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM