Home > database >  Python - Compute Local Minimum In Array Using Prefix Sums
Python - Compute Local Minimum In Array Using Prefix Sums

Time:12-25

I'm trying to solve the Min Avg Two Slice question from Codility.

I came up with the following code:

def solution(S, P, Q):
    weights = {'A': 1, 'C': 2, 'G': 3, 'T': 4}
    retVal = []
    for i in range(0, len(P)): 
        if P[i] == Q[i]: 
            retVal.append(weights[S[P[i]]])
        else: 
            retVal.append(local_min(S, weights, P[i], Q[i]))
    return retVal

minimums = {}
def local_min(S, weights, start, end):
    minVal = weights[S[start]]
    for i in range(start,end 1):
        val = weights[S[i]]
        if val == 1: 
            minimums[i] = 1
            return 1
        if val < minVal: 
            minVal = val
        minimums[i] = minVal
    return minVal

This works fine in terms of correctness, however it has a time complexity of O(n*m) since I'm re-computing the local_min every time and not reusing any results.

I'm trying to use the prefix_sums algorithm here to compute local mins or somehow memoize the computed min values using the minimums object and reuse them in subsequent calls to local_min.

The problem I'm running into is this - lets say we have the following array:

[1, 13, 2, 8, 20, 5]

We could compute an array of smallest values seen up to this point as follows:

For range 0, 6 it would simply be:

[1,1,1,1,1,1]

For 1,6 it would be:

[13, 2, 2, 2, 2]

For 2,6:

[2, 2, 2, 2]

And finally:

[8, 8, 8] and [20, 5]

I'm struggling to see how to adapt this approach to compute the smallest value in a given range and reduce the time complexity of my solution.

CodePudding user response:

The hard part of this problem is proving that there's an easy solution.

In particular, you can prove that you only need to look for slices of length 2 or 3.

Proof: Imagine that there is a slice of length >=4 that has the smallest possible average. We can divide it into two slices -- one consisting of the first 2 elements, and one consisting of the remainder. Neither part can have a smaller average than the whole, since the whole has the smallest possible average, and so both parts must have the same average as the whole, so those initial 2 elements are a valid result that starts at the same place.

So just iterate through the start positions and test all slices of length 2 or 3, and remember the first one with the smallest average.

CodePudding user response:

Lots of options.

  • Segment Tree (best option as for me). O(n) for construction, O(log(n)) for min search. Not so easy to develop using Python.
  • Sqrt Decomposition. O(n) for construction, O(sqrt(n)) for min search. Very easy to develop.
  • Fenwick Tree. O(n) for construction, O(log(n)) for min search. Extremely easy to develop, quite hard to understand how it works.
  • Sparse Table. O(n*log(n)) for construction, O(1) for min search. Quite easy to develop.

All the links contain the implementation, some of them in Python.

  • Related