Python solution to the weekly challenge 325 task 2

Task 2: Final Price:

You are given an array of item prices.

Write a script to find out the final price of each items in the given array.

There is a special discount scheme going on. If there’s an item with a lower or equal price later in the list, you get a discount equal to that later price (the first one you find in order).

A brute force approach is simply to, for each price in the list, search for the first later price that is not greater.

But this has quadratic complexity (O(n^2)). This can be reduced to O(n log n) by instead going through the list backwards, as you go you keeping a sorted list of potential discounts that may apply to earlier prices in the list.

Ideally for this you'd use a data type that is an easily searchable/iterable set, such as a Judy1 array (which is really a set, stored as a tree). Unfortunately, the full Judy interface seems to be only available from the Python 2 pyjudy; the Python 3 judy interface is minimal. So I will just use a list, kept in sorted order and searched using bisect.

sale_prices = []
seen_prices = []
for price in reversed(prices):

First we find where the current price would belong in the seen list, using bisect_right; the element before that (if any) is our discount.

    seen_price_index = bisect.bisect_right(seen_prices, price)
    discount = seen_prices[seen_price_index-1] if seen_price_index > 0 else 0

Now any previously encountered prices greater than the current price are irrelevant, so we can discard them, and add this price:

    if seen_price_index == 0 or seen_prices[seen_price_index-1] != price:
        seen_prices[seen_price_index:] = [price]

Here, the if only serves to prevent (harmless) duplicate prices in our list; it could be omitted and just do the assignment. If we'd originally done a bisect_left, the if would also be unneeded, but the discount code would be slightly more complex.

And insert the sale price:

sale_prices.insert(0, price - discount)

If preferred, this could be appended instead, and the list reversed to restore the original prices order.

full script
in Perl, for comparison

See you next week.