Max interval intersection point - python

I am trying to implement the logic in python. Given a set of intervals, find the interval which has the maximum number of intersections. If input (1,6) (2,3) (4,11), then (1,6) should be returned. This has been answered in below but I have been unable to implement it in python.
given-a-set-of-intervals-find-the-interval-which-has-the-maximum-number-of-inte.
So far I am using the below logic. Any help will be greatly appreciated.
def interval_intersection(intervals):
if len(intervals) ==1:
return intervals
intervals.sort(key=lambda x: x[0])
res =[intervals[0]]
for i in range(1,len(intervals)):
if intervals[i][0] > res[-1][1]:
res.append(intervals[i])
else:
res[-1] = [min(res[-1][0],intervals[i][0]),max(res[-1][1],intervals[i][1])]
return res
Examples:
[[1,5],[5,10],[5,5]]
ans should be [5,5]
In case of tie [5,5] the interval with least number of elements . Here [5,5] has only 1 element in the range ie 5 hence the ans
[[1,2],[3,5]]
no intersection return -1

This is a fairly straightforward implementation of David Eisenstat's algorithm. The only subtleties are:
I assume that all intervals are closed on both ends, which means that sorting events should put starts before ends if they're simultaneous. If you want intervals that are fully open, or open on the right side, this order needs to be reversed.
The returned interval has the most intersections, with ties broken first by smallest length, then by earliest start.
def interval_solve(intervals: Sequence[Sequence[int]]) -> Union[Sequence[int], int]:
start_type = -1 # Assumes all intervals are closed
end_type = 1
events = [(s, start_type, i) for i, (s, e) in enumerate(intervals)]
events.extend((e, end_type, i) for i, (s, e) in enumerate(intervals))
events.sort()
inter_count: Dict[int, int] = {}
start_count = 0
stop_count = 0
for event_time, event_type, event_id in events:
if event_type == start_type:
start_count += 1
inter_count[event_id] = -(stop_count + 1)
else:
stop_count += 1
inter_count[event_id] += start_count
# Find max by most intersections, then by shortest interval, then by earliest start
answer = max(range(len(intervals)),
key=lambda j: (inter_count[j], intervals[j][0] - intervals[j][1]))
if inter_count[answer] == 0:
return -1
return intervals[answer]

The actual idea is pretty simple, we sort the intervals and store some of them with an index and a boolean key for indicating the start or end events.
Then, we just traverse it while counting the end events before an index and the start events. For any index i, interval overlap count is simply, number of start events before - number of end events before (-1).
Finally, we can just check which one has the minimum length in case of multiple solutions.
# https://stackoverflow.com/questions/69426852/max-interval-intersection-point
def max_interval_count(intervals):
interval_sorted = []
for idx, interval in enumerate(intervals):
s, e = interval
interval_sorted.append([s, idx, 0]) # 0 for start
interval_sorted.append([e, idx, 1]) # 1 for end
interval_sorted.sort(key = lambda x: x[0])
print(interval_sorted)
number_of_starts = 0
number_of_ends = 0
overlap_count = {}
for event in interval_sorted:
_, idx, start_end = event
if start_end == 0: # start event
# subtract all the ending before it
overlap_count[idx] = - (number_of_ends)
number_of_starts += 1
else: # end event
overlap_count[idx] += (number_of_starts - 1) # -1 as we should not include the start from the same interval
number_of_ends += 1
print(overlap_count)
ans_idx = -1
max_over_count = 0
min_len_interval = 99999999999
for idx, overl_cnt in overlap_count.items():
if overl_cnt > max_over_count:
ans_idx = idx
max_over_count = overl_cnt
elif overl_cnt == max_over_count and overl_cnt > 0 and (intervals[idx][1] - intervals[idx][0] + 1) < min_len_interval:
min_len_interval = (intervals[idx][1] - intervals[idx][0] + 1)
ans_idx = idx
if ans_idx == -1:
return ans_idx
return intervals[ans_idx]
if __name__ == "__main__":
test_1 = [[1,5],[5,10],[5,5]]
test_2 = [[1,2],[3,5]]
test_3 = [(1,6), (2,3), (4,11)]
ans = max_interval_count(test_1)
print(ans)
print("---------")
ans = max_interval_count(test_2)
print(ans)
print("---------")
ans = max_interval_count(test_3)
print(ans)
print("---------")
[[1, 0, 0], [5, 0, 1], [5, 1, 0], [5, 2, 0], [5, 2, 1], [10, 1, 1]]
{0: 0, 1: 1, 2: 1}
[5, 5]
---------
[[1, 0, 0], [2, 0, 1], [3, 1, 0], [5, 1, 1]]
{0: 0, 1: 0}
-1
---------
[[1, 0, 0], [2, 1, 0], [3, 1, 1], [4, 2, 0], [6, 0, 1], [11, 2, 1]]
{0: 2, 1: 1, 2: 1}
(1, 6)
---------

Related

2D List not calculating properly

I'm trying to do a game of life. There's this weird bug I can't really fix because I don't really know where the problem is? I'm guessing it's in the loop? I don't really know. I tried to debug it using the if total > 0 print(total), and the total is only 2 when it should've been 3. I'm sorry if i'm explaining it confusing because i'm also confused.
def test():
board = [[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]]
#Tracking the neighbor, it shows that there is 3 alive neighbors in
#here.
print(board[2][1])
print(board[2-1][1+1])
print(board[2][1+1])
print(board[2+1][1+1])
return board
def update(grid, N):
newGrid = grid.copy()
for i in range(N):
if i == 0 or i == 4:
continue
for j in range(N):
if j == 0 or j == 4:
continue
total = 0
total = total + grid[i][j-1] #
total = total + grid[i][j+1] #
total = total + grid[i-1][j] #
total = total + grid[i+1][j] #
total = total + grid[i-1][j-1] #
total = total + grid[i-1][j+1] #
total = total + grid[i+1][j-1] #
total = total + grid[i+1][j+1] #
# In here it only states that there's only 2 alive neighbors
# when there should've been 3
if total > 0:
print(total)
# apply Conway's rules
if grid[i][j] == 1:
if (total < 2) or (total > 3):
newGrid[i][j] = 0
elif total == 3:
newGrid[i][j] = 1
else:
if total == 3:
newGrid[i][j] = 1
grid[:] = newGrid[:]
return(grid)
f = 0
zboard = test()
while f <= 3:
print("Generation: " + str(f))
gen = update(zboard, 5)
for i in gen:
print(i)
f += 1
You need to use deepcopy.
When you do newGrid = grid.copy(), since you have a 2D-list, the sublists in newGrid will not be independent from the sublists from grid. Your problem was that grid was updated each time you updated newGrid.
You need to replace this:
newGrid = grid.copy()
by this :
import copy
newGrid = copy.deepcopy(grid)
Here is an example to show you what was happening. cop_1 is a dependent copy whereas cop_2 is an independent one :
board = [[0, 0],
[0, 0]]
cop_1 = board.copy()
import copy
cop_2 = copy.deepcopy(board)
board[0][0] = 3 # change a value of board
print("cop_1[0][0] =", cop_1[0][0])
# cop_1[0][0] = 3
print("cop_2[0][0] =", cop_2[0][0])
# cop_2[0][0] = 0
If you run the code like you posted, you get a mistake because you didn't indent the lines after your function def test(): until return board

Finding Maximum non-negative Subarray in python

I've tried to find the sub-array(s) from a given which contain elements of maximum sum than any other sub array.
Below function has parameter as input a and the output needs to be returned. There can be more than one subarray as their maximum sum can be equal. The code did not seem to be working as expected.
def max_sum_subarray(a):
N, sub_sum, max_sum, subArrays = len(a), 0, 0, {}
p,q=0,0 #starting and ending indices of a max sub arr
for i in range(N):
q=i
sub_sum+=a[i]
if(a[i]<0):
q-=1
if(sub_sum>=max_sum):
if(sub_sum>max_sum):
subArrays.clear()
subArrays[sub_sum]=[(p,q)]
else:
subArrays[sub_sum].append((p,q))
sub_sum=0
p=i+1
if(sub_sum>=max_sum):
if(sub_sum>max_sum):
subArrays.clear()
subArrays[sub_sum]=[(p,q)]
else:
subArrays[sub_sum].append((p,q))
return(subArrays[p:q+1])
When I tried to run for input
a=[ 1, 2, 5, -7, 2, 5 ]
Expected output is [1, 2, 5] but it gave [2, 5] instead. Can anyone please post the solution in python?
It seems like you making this harder than necessary. You can just keep track of max array seen to far and the current one you're pushing into -- you don't really need to care about anything else. When you hit a negative (or the end of the array) decide if the current should be the new max:
def maxSub(a):
max_so_far = []
max_sum = 0
cur = []
for n in a:
if n >= 0:
cur.append(n)
else:
cur_sum = sum(cur)
if cur_sum > max_sum:
max_sum = cur_sum
max_so_far = cur
cur = []
return max([max_so_far, cur], key = sum)
a=[ 1, 2, 5, -7, 2, 5 ]
maxSub(a)
# [1, 2, 5]
Of course itertools.groupby makes this a one-liner:
from itertools import groupby
a=[ 1, 2, 5, -7, 2, 5 ]
max([list(g) for k,g in groupby(a, key=lambda x: x>0) if k == True], key=sum)
For the following conditions:
NOTE 1: If there is a tie, then compare with segment’s length and
return segment which has maximum length
NOTE 2: If there is still a tie, then return the segment with minimum
starting index
Here is my working code in python:
def check(max_arr,curr):
if sum(curr) > sum(max_arr):
max_arr = curr
elif sum(curr) == sum(max_arr):
if len(curr) > len(max_arr):
max_arr = curr
elif len(curr) == len(max_arr):
if max_arr and (curr[0] > max_arr[0]):
max_arr = curr
return max_arr
def maxset(A):
curr = []
max_arr = []
for i in A:
if i >= 0:
curr.append(i)
else:
max_arr = check(max_arr,curr)
curr = []
max_arr = check(max_arr,curr)
return max_arr

Reducing a N-Sum to a Two Sum

I've recently came across a cool algorithm to reduce any problem of the sort "Find n numbers in an array that sum to a target" to a Two Sum problem. However, I am having a hard time understanding one line of the code.
def findNsum(nums, target, N, result, results):
if len(nums) < N or N < 2 or target < nums[0]*N or target > nums[-1]*N: # early termination
return
if N == 2: # two pointers solve sorted 2-sum problem
l,r = 0,len(nums)-1
while l < r:
s = nums[l] + nums[r]
if s == target:
results.append(result + [nums[l], nums[r]])
l += 1
while l < r and nums[l] == nums[l-1]:
l += 1
elif s < target:
l += 1
else:
r -= 1
else: # recursively reduce N
for i in range(len(nums)-N+1):
if i == 0 or (i > 0 and nums[i-1] != nums[i]):
findNsum(nums[i+1:], target-nums[i], N-1, result+[nums[i]], results)
results = []
findNsum(sorted(nums), 0, 3, [], results)
return results
The condition:
if i == 0 or (i > 0 and nums[i-1] != nums[i]):
Does not make sense to me. Why do I have to check if nums[i-1] != nums[i]? If I try it out with, say, with nums = [-1, 0, 1, 2, 2, -1, -4], I get [[-4, 2, 2], [-1, -1, 2], [-1, 0, 1]] with the condition. If I take it out I get [[-4, 2, 2], [-1, -1, 2], [-1, 0, 1], [-1, 0, 1]]. Can any one make sense of this?
Cheers!
The condition nums[i-1] != nums[i] is to avoid creating duplicate solutions when picking the first element, which can see in your output in the second example. This problem wants to find all unique solutions, not all possible solutions, hence we want to drop the second [-1,0,1]

Function that returns tribonnacci series up to a number

I am trying to solve an exercise that requires me to write a function that takes as input an integer which then returns a list of tribonacci terms up until the input value. I have been "successful" for the most part but an extra term is output as well. This is my code:
def tribonacci(m):
tribs = [0, 0, 1]
if m == 0 or m == 1:
tribs = [0, 0]
elif m == 2:
tribs = [0, 0, 1]
else:
while tribs[-1] < m:
tribs.append(tribs[-1] + tribs[-3] + tribs[-2])
return tribs
I understand that the issue is the while loop which runs an extra iteration because the last element is still not greater than m. However, I can't see immediately how to fix this. I would resort to a while-else loop, but I'd like to see some other suggestions.
Just compare the term that is about to be genrated with m, like this:
def tribonacci(m):
tribs = [0, 0, 1]
if m == 0 or m == 1:
tribs = [0, 0]
elif m == 2:
tribs = [0, 0, 1]
else:
while tribs[-1] + tribs[-3] + tribs[-2] < m:
tribs.append(tribs[-1] + tribs[-3] + tribs[-2])
return tribs

Finding majority votes on -1s, 1s and 0s in list - python

How to find the majority votes for a list that can contain -1s, 1s and 0s?
For example, given a list of:
x = [-1, -1, -1, -1, 0]
The majority is -1 , so the output should return -1
Another example, given a list of:
x = [1, 1, 1, 0, 0, -1]
The majority vote would be 1
And when we have a tie, the majority vote should return 0, e.g.:
x = [1, 1, 1, -1, -1, -1]
This should also return zero:
x = [1, 1, 0, 0, -1, -1]
The simplest case to get the majority vote seem to sum the list up and check whether it's negative, positive or 0.
>>> x = [-1, -1, -1, -1, 0]
>>> sum(x) # So majority -> 0
-4
>>> x = [-1, 1, 1, 1, 0]
>>> sum(x) # So majority -> 1
2
>>> x = [-1, -1, 1, 1, 0]
>>> sum(x) # So majority is tied, i.e. -> 0
0
After the sum, I could do this check to get the majority vote, i.e.:
>>> x = [-1, 1, 1, 1, 0]
>>> majority = -1 if sum(x) < 0 else 1 if sum(x)!=0 else 0
>>> majority
1
>>> x = [-1, -1, 1, 1, 0]
>>> majority = -1 if sum(x) < 0 else 1 if sum(x)!=0 else 0
>>> majority
0
But as noted previously, it's ugly: Python putting an if-elif-else statement on one line and not pythonic.
So the solution seems to be
>>> x = [-1, -1, 1, 1, 0]
>>> if sum(x) == 0:
... majority = 0
... else:
... majority = -1 if sum(x) < 0 else 1
...
>>> majority
0
EDITED
But there are cases that sum() won't work, #RobertB's e.g.
>>> x = [-1, -1, 0, 0, 0, 0]
>>> sum(x)
-2
But in this case the majority vote should be 0!!
I am assuming that votes for 0 count as votes. So sum is not a reasonable option.
Try a Counter:
>>> from collections import Counter
>>> x = Counter([-1,-1,-1, 1,1,1,1,0,0,0,0,0,0,0,0])
>>> x
Counter({0: 8, 1: 4, -1: 3})
>>> x.most_common(1)
[(0, 8)]
>>> x.most_common(1)[0][0]
0
So you could write code like:
from collections import Counter
def find_majority(votes):
vote_count = Counter(votes)
top_two = vote_count.most_common(2)
if len(top_two)>1 and top_two[0][1] == top_two[1][1]:
# It is a tie
return 0
return top_two[0][0]
>>> find_majority([1,1,-1,-1,0]) # It is a tie
0
>>> find_majority([1,1,1,1, -1,-1,-1,0])
1
>>> find_majority([-1,-1,0,0,0]) # Votes for zero win
0
>>> find_majority(['a','a','b',]) # Totally not asked for, but would work
'a'
You could use statistics.mode if you were using python >= 3.4 ,catching a StatisticsError for when you have no unique mode:
from statistics import mode, StatisticsError
def majority(l):
try:
return mode(l)
except StatisticsError:
return 0
The statistics implementation itself uses a Counter dict:
import collections
def _counts(data):
# Generate a table of sorted (value, frequency) pairs.
table = collections.Counter(iter(data)).most_common()
if not table:
return table
# Extract the values with the highest frequency.
maxfreq = table[0][1]
for i in range(1, len(table)):
if table[i][1] != maxfreq:
table = table[:i]
break
return table
def mode(data):
"""Return the most common data point from discrete or nominal data.
``mode`` assumes discrete data, and returns a single value. This is the
standard treatment of the mode as commonly taught in schools:
>>> mode([1, 1, 2, 3, 3, 3, 3, 4])
3
This also works with nominal (non-numeric) data:
>>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
'red'
If there is not exactly one most common value, ``mode`` will raise
StatisticsError.
"""
# Generate a table of sorted (value, frequency) pairs.
table = _counts(data)
if len(table) == 1:
return table[0][0]
elif table:
raise StatisticsError(
'no unique mode; found %d equally common values' % len(table)
)
else:
raise StatisticsError('no mode for empty data')
Another way using a Counter and catching an empty list:
def majority(l):
cn = Counter(l).most_common(2)
return 0 if len(cn) > 1 and cn[0][1] == cn[1][1] else next(iter(cn),[0])[0]
You can count occurences of 0 and test if they are majority.
>>> x = [1, 1, 0, 0, 0]
>>> if sum(x) == 0 or x.count(0) >= len(x) / 2.0:
... majority = 0
... else:
... majority = -1 if (sum(x) < 0) else 1
... majority
0
This solution is based on counting occurrences and sorting:
import operator
def determineMajority(x):
'''
>>> determineMajority([-1, -1, -1, -1, 0])
-1
>>> determineMajority([1, 1, 1, 0, 0, -1])
1
>>> determineMajority([1, 1, 1, -1, -1, -1])
0
>>> determineMajority([1, 1, 1, 0, 0, 0])
0
>>> determineMajority([1, 1, 0, 0, -1, -1])
0
>>> determineMajority([-1, -1, 0, 0, 0, 0])
0
'''
# Count three times
# sort on counts
xs = sorted(
[(i, x.count(i)) for i in range(-1,2)],
key=operator.itemgetter(1),
reverse=True
)
if xs[0][1] > xs[1][1]:
return xs[0][0]
else:
# tie
return 0
if __name__ == '__main__':
import doctest
doctest.testmod()
Additionally, there is one if statements. As mentioned in the comments it is undefined what happens with
x = [1, 1, 0, 0, -1]
# These are your actual votes
votes = [-1, -1, -1, -1, 0]
# These are the options on the ballot
ballot = (-1, 0, 1)
# This is to initialize your counters
counters = {x: 0 for x in ballot}
# Count the number of votes
for vote in votes:
counters[vote] += 1
results = counters.values().sort()
if len(set(values)) < len(ballot) and values[-1] == values [-2]:
# Return 0 if there's a tie
return 0
else:
# Return your winning vote if there isn't a tie
return max(counters, key=counters.get)
A very simple approach.
a = [-1, -1, -1, -1, 0] # Example
count = {}
for i in a:
if i not in count:
count[i] = 1
else:
count[i] += 1
m_count = max(count.values())
for key in count:
if count[key] == m_count:
print key
In the above example the output will be -1,
however if there is a tie, both the keys will be printed.
I believe this works for all provided test cases. Please let me know if I did something wrong.
from collections import Counter
def fn(x):
counts = Counter(x)
num_n1 = counts.get(-1, 0)
num_p1 = counts.get(1, 0)
num_z = counts.get(0, 0)
if num_n1 > num_p1:
return -1 if num_n1 > num_z else 0
elif num_p1 > num_n1:
return 1 if num_p1 > num_z else 0
else:
return 0
from collections import Counter
result = Counter(votes).most_common(2)
result = 0 if result[0][1] == result[1][1] else result[0][0]
Error handling for empty votes lists or votes lists with a set cardinality of 1 is trivial and left as an exercise for the reader.
This works with any number of candidates. If there is a tie between two candidates it returns zero else it returns candidate with most votes.
from collections import Counter
x = [-1, -1, 0, 0, 0, 0]
counts = list((Counter(x).most_common())) ## Array in descending order by votes
if len(counts)>1 and (counts[0][1] == counts[1][1]): ## Comparing top two candidates
print 0
else:
print counts[0][0]
We compare only two candidates because if there is a tie between two candidates it should return 0 and it doesn't depend on third candidate value
An obvious approach is making a counter and updating it according to the data list x. Then you can get the list of numbers (from -1, 0, 1) that are the most frequent. If there is 1 such number, this is what you want, otherwise choose 0 (as you requested).
counter = {-1: 0, 0: 0, 1: 0}
for number in x:
counter[number] += 1
best_values = [i for i in (-1, 0, 1) if counter[i] == max(counter.values())]
if len(best_values) == 1:
majority = best_values[0]
else:
majority = 0
You don't need anything but built-in list operators and stuff, no need to import anything.
votes = [ -1,-1,0,1,0,1,-1,-1] # note that we don't care about ordering
counts = [ votes.count(-1),votes.count(0),votes.count(1)]
if (counts[0]>0 and counts.count(counts[0]) > 1) or (counts[1]>0 and counts.count(counts[1])>1):
majority=0
else:
majority=counts.index(max(counts))-1 # subtract 1 as indexes start with 0
print majority
3d line puts counts of respective votes in a new list, and counts.index() shows us which list position we find the max votes.
I would dare to say that this should be about as pythonic as it can, without getting into eye-gouging oneliners.
Upd: rewrote without text strings and updated to return 0 in case of several equal results (didnt notice this in the original post), added an IF for case if only one vote, eg votes=[-1]
from collections import Counter
def find_majority_vote(votes):
counter = Counter(votes)
most_common = counter.most_common(2)
if len(most_common)==2:
return 0 if most_common[0][1] == most_common[1][1] else most_common[0][0]
else:
return most_common[0][0]
import numpy as np
def fn(vote):
n=vote[np.where(vote<0)].size
p=vote[np.where(vote>0)].size
ret=np.sign(p-n)
z=vote.size-p-n
if z>=max(p,n):
ret=0
return ret
# some test cases
print fn(np.array([-1,-1, 1,1,1,1,0,0,0,0,0,0,0,0]))
print fn(np.array([-1, -1, -1, 1,1,1,0,0]))
print fn(np.array([0,0,0,1,1,1]))
print fn(np.array([1,1,1,1, -1,-1,-1,0]))
print fn(np.array([-1, -1, -1, -1, 1, 0]))

Categories

Resources