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..
CodePudding user response:
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);
CodePudding user response:
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
andend
members if the latter smaller than the former).