Sunday, June 07, 2015

get interval with max discount given discounts for intervals

There are discounts on particular time intervals. Find the interval where maximum discount is available. Time interval could be days or time.

Example:
Day 1 - 5 => 10%
Day 2 - 8 =>  5%
Day 4 - 6 => 20%

Interval with max discount:
Day 4 - 5 => 35%
interval:
    start, end
    discount

// time: O(nlogn)
getmaxdiscount(intervals):
    times = split(intervals) // O(nlogn)
    maxdiscount = getmaxdiscount(times) // O(n)
    return maxdiscount

time:
    value
    discount
    isstart
    
// split interval into time
// time: O(nlogn)
split(intervals):
    times = new
    foreach interval in intervals:
        times.add(new time(interval.start, interval.discount, true))
        times.add(new time(interval.end, interval.discount, false))
    // when value is same, the start time should come first
    return times.orderby(value, !isstart)

// time: O(n)
getmaxdiscount(times):
    discount = 0
    start, end = null, maxdiscount = 0
    foreach time in times:
        if time.isstart: // time is start
            discount += time.discount
            if discount > maxdiscount:
                maxdiscount = discount
                start = time.value
                end = null
        else: // time is end
            if discount == maxdiscount:
                end = time.value
            discount -= time.discount
    return { start, end, maxdiscount }

--example:
Day 1 + 10%, 10%, {Days 1-?, 10%}
Day 2 +  5%, 15%, {Days 2-?, 15%}
Day 4 + 20%, 35%, {Days 4-?, 35%}
Day 5 - 10%, 25%, {Days 4-5, 35%} --max
Day 6 - 20%,  5%, 
Day 8 -  5%,  0%, 

There could multiple intervals with same max discount so capture the longer interval.
// time: O(n)
getmaxdiscount(times):
    discount = 0
    start, end = null, maxdiscount = 0
    max = null
    foreach time in times:
        if time.isstart: // time is start
            discount += time.discount
            if discount >= maxdiscount: // = to capture longer interval
                maxdiscount = discount
                start = time.value
                end = null
        else: // time is end
            if discount == maxdiscount:
                end = time.value
                curr = new interval(start, end, maxdiscount)
                if max == null || curr > max: //operator > overloaded
                    max = curr
            discount -= time.discount
    return max

interval: icomparable
    // compare discount first, length of interval second
    compare(other):
        c = discount.compare(other.discount)
        if c == 0:
            c = (end - start).compare(other.end - other.start)
        return c

No comments:

Post a Comment