DEV Community

Discussion on: Write better code: Day 1 - Highest Product

 
qm3ster profile image
Mihail Malo • Edited

Okay, I think I got it:

import math


def get_product_of_3(array_of_ints):
    if len(array_of_ints) < 3:
        return 0

    min_max = -math.inf
    min_max_i = 0
    maxes = [min_max, min_max, min_max]
    max_neg = 0
    max_neg_i = 0
    negs = [0, 0]
    for int in array_of_ints:
        if int > min_max:
            maxes[min_max_i] = int
            min_max_i, min_max = min(enumerate(maxes), key=lambda x: x[1])
        if int < max_neg:
            negs[max_neg_i] = int
            max_neg_i, max_neg = max(enumerate(negs), key=lambda x: x[1])

    prod_maxes = maxes[0]*maxes[1]*maxes[2]
    prod_negs = negs[0]*negs[1]
    # This condition is only needed for `[n,p,p]`, to not return the invalid product of `0` when the product of maxes is negative. 
    if prod_negs != 0:
        return max(prod_negs*max(maxes), prod_maxes)
    return prod_maxes

If we instead explicitly return the product of 3 inputs, this condition is no longer needed:

import math


def get_product_of_3(array_of_ints):
    if len(array_of_ints) < 3:
        return 0
    if len(array_of_ints) == 3:
        return array_of_ints[0]*array_of_ints[1]*array_of_ints[2]

    min_max = -math.inf
    min_max_i = 0
    maxes = [min_max, min_max, min_max]
    max_neg = 0
    max_neg_i = 0
    negs = [0, 0]
    for int in array_of_ints:
        if int > min_max:
            maxes[min_max_i] = int
            min_max_i, min_max = min(enumerate(maxes), key=lambda x: x[1])
        if int < max_neg:
            negs[max_neg_i] = int
            max_neg_i, max_neg = max(enumerate(negs), key=lambda x: x[1])

    prod_maxes = maxes[0]*maxes[1]*maxes[2]
    prod_negs = negs[0]*negs[1]
    return max(prod_negs*max(maxes), prod_maxes)

Another possible optimization, for input such as [...-100,-99,-98,-97,1,-96,-95,-94...] is to stop expecting the "all negatives" case. This can easily be done by resetting all negative maxes to 0, so that incoming negatives are always smaller:

import math


def get_product_of_3(array_of_ints):
    if len(array_of_ints) < 3:
        return 0
    if len(array_of_ints) == 3:
        return array_of_ints[0]*array_of_ints[1]*array_of_ints[2]

    awaiting_not_negatve = True
    min_max = -math.inf
    min_max_i = 0
    maxes = [min_max, min_max, min_max]
    max_neg = 0
    max_neg_i = 0
    negs = [0, 0]
    for int in array_of_ints:
        if int > min_max:
            maxes[min_max_i] = int
            if awaiting_not_negatve and int >= 0:
                awaiting_not_negatve = False
                for i, v in enumerate(maxes):
                    if v < 0:
                        maxes[i] = 0
            min_max_i, min_max = min(enumerate(maxes), key=lambda x: x[1])
        if int < max_neg:
            negs[max_neg_i] = int
            max_neg_i, max_neg = max(enumerate(negs), key=lambda x: x[1])

    prod_maxes = maxes[0]*maxes[1]*maxes[2]
    prod_negs = negs[0]*negs[1]
    return max(prod_negs*max(maxes), prod_maxes)