简体   繁体   中英

Best way to return minimum number of ranges from a collection of ranges

I'm new to Python and SWE in general so excuse the simple questions. I was given the following coding challenge by an interviewer. And I came up with the following solution. But I was passed over becuase it didnt meet their performance criteria. I was wondering if anyone could give me pointers on how I can do better on this question and in general for questions like this. I've found other answers solving the question, but I wanted specific answers to my implementation.

Here is the Feedback I recieved:

  1. The while (zip_range_list): line sticks out: you don't see a lot of while loops in Python, you don't have to put parentheses around the test expression, and solving this problem with a while loop is a weird thing to do. Why are while loops a bad idea?
  2. Adding a range to reduced_zip_ranges before it's reduced, and then continually referring to the element you just added as reduced_zip_ranges[-1] instead of having a separate binding for it reads awkwardly. Why is this awkward?
  3. The construct range_check = range(low-1, high+2) may be correct, but it's both strange to look at and ridiculously space-wasteful: instead of comparing endpoints he builds a list of the entire range of numbers just to check membership in that range. He builds these over and over again in a loop within a loop. I see the point here. I was trying to avoid a long if-statement. Wasn't a good idea.
  4. Speaking of "loop within a loop", this is an O(N-squared) algorithm when it could have been O(N) after the sort. I guess I overlooked this, I see 0(n^2) now. How can I avoid this?
  5. The routine has two different non-exceptional return points; the one within the loop is unnecessary (the code works as well with it commented out).

PROBLEM Given a collection of zip code ranges (each range includes both their upper and lower bounds), provide an algorithm that produces the minimum number of ranges required to represent the same coverage as the input.

Input: [[14,17], [4,7], [2,5], [10,12] , [15,16], [4,9], [11,13]]
Output: [[2,17]]


# Implementation
def zip_range_reducer(zip_range_list):

    if not zip_range_list:
        raise Exception("Empty list of ranges provided!")

    reduced_zip_ranges = []

    zip_range_list.sort()

    while (zip_range_list):
        no_overlap_ranges = []
        reduced_zip_ranges.append(zip_range_list[0])
        if len(zip_range_list) == 1:
            return reduced_zip_ranges
        zip_range_list.pop(0)
        for zip_range in zip_range_list:
            low, high = reduced_zip_ranges[-1][0], reduced_zip_ranges[-1][1]
            range_check = range(low-1, high+2)
            if zip_range[0] in range_check or zip_range[1] in range_check:
                reduced_zip_ranges[-1][0] = min(reduced_zip_ranges[-1][0], zip_range[0])
                reduced_zip_ranges[-1][1] = max(reduced_zip_ranges[-1][1], zip_range[1])
            else:
                no_overlap_ranges.append(zip_range)
        zip_range_list = no_overlap_ranges

    return reduced_zip_ranges

Also

Here is a O(n) solution. [Excluding the complexity of sorting]

def reduceRangeList(ranges):
    # sorting the list based on the lower limit, and then based on size as tie breaker
    # note we need the bigger ranges to come before the smaller ranges
    ranges.sort(key= lambda pair : (pair[0], - pair[1]))

    reduced= []     # new set of ranges are stored here

    # we use a parent range to decide if a range is inside other ranges
    parent= ranges[0]

    # this will for sure be part of the solution,
    # because it is the largest, leftmost range
    reduced.append(ranges[0])

    for x in ranges:
        if parent[0] <= x[0] and x[1] <= parent[1]:
            # this range is completely within another range, ignore!
            continue
        elif x[0] <= parent[1]:
            # this range is partially inside the parent range
            # so we set the parent to cover this two range
            parent= [parent[0], x[1]]
        else:
            #this range is completely outside the parent range
            parent= x

        # If the range is completely or partially outside other ranges...
        # I'm placing it here to avoid duplicate code
        reduced.append(x)

    return reduced




def main():
    ranges= [[1,5], [2, 4], [6, 7], [2,7], [9,10]]
    # ranges= [[1,5], [1,4], [2, 6]]
    # ranges= [[1,2], [3,4], [5,6], [1,6], [6,7], [4, 8]]


    reduced= reduceRangeList(ranges)

    print(reduced)

if __name__ == '__main__':
    main()

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