Since the intervals are just number pairs, you can encode them in a list.
Text Only
123
[ (a b) (c d) ]
Here you have a list length=4, contains number of intervals=2
Therefore you can make use of the property of a plain list, you can do binary search, also slicing on it.
For example:
Text Only
123
A = [ (1 4) (7 9) ]
next interval = (3, 6) = (lo, hi)
Lets consider 3=lo. We need know where should 3 belongs to A, namely, is 3 within some interval or outside of any interval. Here you use binary search to find the point of insert.
This is a odd number. odd number means it is within the interval at index 0~1. Because:
Text Only
123456
intervals = [ (a b) (c d) ... ]
index = [ 0 1 2 3 ... ]
index is odd even odd even...
odd insert index ==means==> after a even index ==means==> (start, insert, end)
Thus by finding whether the index returned by find() is even or edd.
You also know whether it is being inserted within or outside a particular interval. That is:
Text Only
12345
A = [ (1 4) (7 9) ]
next = (3 6)
for 3: find(A, 3) => 1 => odd => within particaular interval
for 6: find(A, 6) => 2 => even => outside of any interval
As 3 is within particular interval, it is overlapped with that particular interval, thus is consecutive.
Therefore you can combine them as one single interval.
Before going into the details of handling lo and hi, first you need to know how to do the finishing task.
Let say this is the result. (1, 4) combine with (lo, hi), to form a new (1, hi) interval, replacing the old one.
Text Only
1234
A = [ (1 4) (7 9) ]
next = (lo hi)
new_A = [ (1 hi) (7 9) ]
In general case, there you can divide the list into three parts:
Text Only
123
[ <left intervals> <combined intervals> <righ intervals> ]
[ <left intervals> ( 1 lo 4 hi ) <righ intervals> ]
What you need to do is to split the list into three parts, replace the middle part with combined intervals, and then put these three parts back together as the new list.
In order to achive this, you have to find out the lower and upper limits for slicing.
For example, for a completely disjointed new interval:
frombisectimportbisectasfindA=[(14)(79)]new=(lo,hi)i=find(A,lo)ifi%2:# i is odd# case b# since lo is within the interval, # the lowest point is left boundary of that intervallowest=A[i-1]else:# i is even# case a# if lo==1, this is True. # if lo<1, this is also True.# if lo<1, it means that (1, 4) is inside (lo, hi),# so the lowest point is lo.iflo<=A[i]:lowest=lo# case celse:# A[i-1] < lo# disjointifA[i-1]<lo:lowest=lo# connected else:lowest=A[i-2]
frombisectimportbisectasfindA=[(14)(79)]new=(lo,hi)deffind_lowest(A,lo):i=find(A,lo)# boundary caseifi==0:lowest=0else:# i is odd, case bifi%2:# since lo is within the interval, # the lowest point is left boundary of that intervallowest=A[i-1]# i is even, case celse:# disjointifA[i-1]<lo:lowest=lo# connected else:lowest=A[i-2]returnlowest
frombisectimportbisectasfindA=[(14)(79)]new=(lo,hi)deffind_lowest(A,lo):i=find(A,lo)# boundary caseifi==0:lowest=0,0# limit@0else:# i is odd, case bifi%2:# since lo is within the interval, # the lowest point is left boundary of that intervallowest=A[i-1],i-1# i is even, case celse:# disjointifA[i-1]<lo:lowest=lo,i# connected else:lowest=A[i-2],i-2returnlowest>>>find_lowest(A,0)(0,0)>>>find_lowest(A,1)(1,0)>>>find_lowest(A,3)(3,0)>>>find_lowest(A,4)(4,0)>>>find_lowest(A,5)(5,2)
frombisectimportbisectasfindA=[(14)(79)]new=(lo,hi)deffind_highest(A,hi):i=find(A,hi)# boundary caseifi==len(A):highest=hi,len(A)else:# i is odd, case bifi%2:# since hi is within the interval, # the highest point is right boundary of that intervalhighest=A[i],i# be careful with python indexing# i is even, case aelse:ifhi<A[i]:# disjointed highest=hi,ielse:highest=A[i+1],i+2# be careful with python indexing# [ ... hi 7 9 ... ] # ^ find(A,i) return index:i of this positionreturnhighest>>>find_highest(A,6)(6,2)>>>find_right_lowest(A,7)(7,3)>>>find_right_lowest(A,8)(8,3)>>>find_right_lowest(A,9)(9,3)>>>find_right_lowest(A,10)(10,4)
deffind_maximum_len(intervals):maximun=0A=[]fornew_intervalinintervals:# process the new_interval hereis_this_max=combined_interval[-1]-combined_interval[0]ifis_this_max>maximun:maximum=is_this_maxreturni
frombisectimportbisectasfinddeffind_lowest(A,lo):i=find(A,lo)# boundary caseifi==0:lowest=0,0# limit@0else:# i is odd, case bifi%2:# since lo is within the interval, # the lowest point is left boundary of that intervallowest=A[i-1],i-1# i is even, case celse:# disjointifA[i-1]<lo:lowest=lo,i# connected else:lowest=A[i-2],i-2returnlowestdeffind_highest(A,hi):i=find(A,hi)# boundary caseifi==len(A):highest=hi,len(A)else:# i is odd, case bifi%2:# since hi is within the interval, # the highest point is right boundary of that intervalhighest=A[i],i# be careful with python indexing# i is even, case aelse:ifhi<A[i]:# disjointed highest=hi,ielse:highest=A[i+1],i+2# be careful with python indexing# [ ... hi 7 9 ... ] # ^ find(A,i) return index:i of this positionreturnhighestdeffind_maximum_len(intervals):maximun=0A=[]fornew_intervalinintervals:lo,hi=new_interval# combine intervalslo,lo_limit=find_lowest(A,lo)hi,up_limit=find_highest(A,hi)# update the listA=A[:lo_limit]+[lo,hi]+A[up_limit:]# is this the largest consecutive interval?leng=lo-hiifleng>maximun:maximum=lengreturnmaximun+1>>>intervals=[(1,4),(7,9),(5,8)]>>>find_maximum_len(intervals)5# (5 6 7 8 9)
frombisectimportbisectasfinddeffind_lowest(A,lo):i=find(A,lo)# boundary caseifi==0:lowest=0,0# limit@0else:# i is odd, case bifi%2:# since lo is within the interval, # the lowest point is left boundary of that intervallowest=A[i-1],i-1# i is even, case celse:# disjointifA[i-1]<lo-1:#--- now comparing with lo-1lowest=lo,i# connected else:lowest=A[i-2],i-2returnlowestdeffind_highest(A,hi):i=find(A,hi)# boundary caseifi==len(A):highest=hi,len(A)else:# i is odd, case bifi%2:# since hi is within the interval, # the highest point is right boundary of that intervalhighest=A[i],i# be careful with python indexing# i is even, case aelse:ifhi+1<A[i]:#--- now comparing with hi+1# disjointed highest=hi,ielse:highest=A[i+1],i+2# be careful with python indexing# [ ... hi 7 9 ... ] # ^ find(A,i) return index:i of this positionreturnhighestdeffind_maximum_len(intervals):maximun=0A=[]fornew_intervalinintervals:lo,hi=new_interval# combine intervalslo,lo_limit=find_lowest(A,lo)hi,up_limit=find_highest(A,hi)# update the listA=A[:lo_limit]+[lo,hi]+A[up_limit:]# is this the largest consecutive interval?leng=lo-hiifleng>maximun:maximum=lengreturnmaximun+1>>>intervals=[(1,4),(7,9),(5,8)]>>>find_maximum_len(intervals)9# (1 2 3 4 5 6 7 8 9)
In the previous section you can see that there is only 2 point where we have +-some value to incooperate with the idea of interval-width of 1. Therefore this can be parameterize and process any arbitrary interval-width.
frombisectimportbisectasfinddeffind_lowest(A,lo,r=1):i=find(A,lo)# boundary caseifi==0:lowest=0,0# limit@0else:# i is odd, case bifi%2:# since lo is within the interval, # the lowest point is left boundary of that intervallowest=A[i-1],i-1# i is even, case celse:# disjointifA[i-1]<lo-r:#--- parametrizelowest=lo,i# connected else:lowest=A[i-2],i-2returnlowestdeffind_highest(A,hi,r=1):i=find(A,hi)# boundary caseifi==len(A):highest=hi,len(A)else:# i is odd, case bifi%2:# since hi is within the interval, # the highest point is right boundary of that intervalhighest=A[i],i# be careful with python indexing# i is even, case aelse:ifhi+r<A[i]:#--- parametrize# disjointed highest=hi,ielse:highest=A[i+1],i+2# be careful with python indexing# [ ... hi 7 9 ... ] # ^ find(A,i) return index:i of this positionreturnhighestdeflow_and_high(A,lo,hi,r=1):returnfind_lowest(A,lo,r),find_highest(A,hi,r)deffind_maximum_len(intervals,r=1):maximun=0A=[]fornew_intervalinintervals:lo,hi=new_interval# combine intervals(lo,lo_limit),(hi,up_limit)=low_and_high(A,lo,hi,r)# update the listA=A[:lo_limit]+[lo,hi]+A[up_limit:]# is this the largest consecutive interval?leng=lo-hiifleng>maximun:maximum=lengreturnmaximun+1>>>intervals=[(1,4),(7,9),(5,8)]>>>r=1>>>find_maximum_len(intervals,r)9# (1 2 3 4 5 6 7 8 9)