Hi I have a problem as below:
Given a set of n segments {[a0, b0], [a1, b1], . . . , [an-1, bn-1]} with integer coordinates on a line, find the minimum number m of points such that each segment contains at least one point. That is, find a set of integers X of the minimum size such that for any segment [ai,bi] there is a point x ∈ X such that ai ≤ x ≤ bi.
Input Format: The first line of the input contains the number n of segments. Each of the following n lines contains two integers ai and bi (separated by a space) defining the coordinates of endpoints of the i-th segment.
Output Format: Output the minimum number m of points on the first line and the integer coordinates of m points (separated by spaces) on the second line. You can output the points in any order. If there are many such sets of points, you can output any set. (It is not difficult to see that there always exist a set of points of the minimum size such that all the coordinates of the points are integers.)
Sample 1:
Input: 3
1 3
2 5
3 6
Output: 1 3
Explanation:
In this sample, we have three segments: [1,3],[2,5],[3,6] (of length 2,3,3 respectively). All of them contain the point with coordinate 3: 1 ≤3 ≤3, 2 ≤3 ≤5, 3 ≤ 3 ≤ 6.
Sample 2:
Input: 4
4 7
1 3
2 5
5 6
Output: 2
3 6
Explanation: The second and the third segments contain the point with coordinate 3 while the first and the fourth segments contain the point with coordinate 6. All the four segments cannot be covered by a single point, since the segments [1, 3] and [5, 6] are disjoint.
Solution: The greedy choice is selecting the minimum right endpoint. Then remove all segments that contains that endpoint. Keep choosing minimum right endpoint and removing segments.
I followed the solution. I found the minimum right endpoint, removed all segments that contain that endpoint in my code. Then execute the function again with the new segments list (Keep choosing minimum right endpoint and removing segments - Recursive) but I'm stuck with the order of my code and can't make it works.
list_time = [[4,7],[1,3],[2,5],[5,6]]
def check_inside_range(n, lst): #Function to check if a number is inside the range of start and end of a list
#for example 3 is in [3,5], 4 is not in [5,6], return False if in
if lst[1]-n>=0 and n-lst[0]>=0:
return False
else:
return True
def lay_chu_ki(list_time):
list_time.sort(key = lambda x: x[1]) #Sort according to the end of each segments [1,3],[2,5],[5,6],[4,7]
first_end = list_time[0][1] #Selecting the minimum right endpoint
list_after_remove = list(filter(lambda x: check_inside_range(first_end, x),list_time))
#Remove all segments that contains that endpoint
lay_chu_ki(list_after_remove) #Keep doing the function again with new segments list
#(Keep choosing minimum right endpoint and removing segments)
return first_end #I don't know where to put this line.
print(lay_chu_ki(list_time))
As you can see, I've already done 3 steps: Selecting the minimum right endpoint; Remove all segments that contains that endpoint; Keep choosing minimum right endpoint and removing segments but it won't work somehow. I tried to print two numbers 3 and 6 first (the return result of each recursive call). I also tried to create a count
variable to count each recursive call (count =1
) but it didn't work too since it reset count = 0
for each call.
CodePudding user response:
I think recursion overcomplicates the implementation. While it's still feasible, you have to pass in a bunch of extra parameters, which could be difficult to track. In my opinion, it's much simpler to implement this approach iteratively.
Also, your approach repeatedly uses filter()
and list()
, which takes linear time every time you do it (to clarify, "linear" means linear in the size of the input list). In the worst case, you would perform that operation for every element in the list, which means that the runtime of your original implementation is quadratic (assuming you fix the existing issues with your code). This approach avoids that by making a single pass through the list:
def lay_chu_ki(list_time):
list_time.sort(key=lambda x: x[1])
idx = 0
selected_points = []
while idx != len(list_time):
selected_point = list_time[idx][1]
while idx != len(list_time) and list_time[idx][0] <= selected_point:
idx = 1
selected_points.append(selected_point)
return selected_points
result = lay_chu_ki(list_time)
print(len(result))
print(' '.join(map(str, result)))
With the given list, this outputs:
2
3 6