How to find highest product of k elements in an array of n length, where k n

2024/10/14 18:13:58

I recently tried the question for the highest product of 3 elements. Now I am trying to do it for the k elements. Let's say from 3 now it is asking for 4 elements. I tried to write a generic function so it could handle for any k elements within the array. The algo has to be in O(n) just like the one with 3 elements is.

 def highest_product_sol(input):high = max(input[0],input[1])low = min(input[0],input[1])max_prod_2 = input[0] * input[1]low_prod_2 = input[0] * input[1]max_prod_3 = max_prod_2 * input[2]prod_2_high = input[0] * input[1]prod_2_low = input[0] * input[1]for i in range(2,len(input)):val = input[i]max_prod_3 = max(max_prod_3,max_prod_2*val,low_prod_2*val)prod_2_high = high * valprod_2_low =  low * valmax_prod_2 = max(max_prod_2,prod_2_high)low_prod_2 = min(low_prod_2,prod_2_high)high = max(high,val)low = min(low,val)return (max_prod_2,low_prod_2,max_prod_3)def highest_product_num(input,num):high = max(input[0:num - 1])low = min(input[0:num - 1])print("max",high)print("min",low)prod_high_minus_1 = 1prod_low_minus_1 = 1for n in range(0,num-1):prod_high_minus_1 *= input[n]prod_low_minus_1 *= input[n]max_prod_n_1 = prod_high_minus_1min_prod_n_1 = prod_high_minus_1max_prod_n = prod_high_minus_1 * input[num-1]for i in range(num,len(input)):val = input[i]max_prod_n = max(max_prod_n,max_prod_n_1*val,min_prod_n_1*val)prod_high_minus_1 = high * valprod_low_minus_1 =  low * valmax_prod_n_1 = max(max_prod_n_1,prod_high_minus_1)min_prod_n_1 = min(min_prod_n_1,prod_low_minus_1)high = max(high,val)low = min(low,val)return max_prod_n
test_input = [[1,2,3,4,5,6,7,8],[1,-2,3,4,5,100,2,3,1],[-10,-10,1,3,2][1000,7,-6,2,2]]
print(test_input)for i in test_input:print(highest_product_num(i,4),"\n")# correct `results`
# 1680
# 6000
# 600
Answer

O(n) solution in numpy, stress-tested on the 4 example lists and @Stefan Pochmann's merciless auto test script. Big thanks to Stefan, without whose input a couple of severe bugs would have gone unnoticed.

import numpy as npdef kmaxprod_v2(data, k):if len(data) < k:return np.nandata = np.asanyarray(data)# for integer dtypes convert to python ints to have unlimited range for the# final productdfp = data.astype(object) if data.dtype in (int, np.int64, np.int32, np.int16, np.int8) else data# np.argpartition raises an exception if len(data) == k, thereforeif len(data) == k:return np.prod(dfp)neg = data <= 0# if k is odd and there are no positive elements we must settle for the# least negativeif k % 2 == 1 and np.count_nonzero(neg) == len(data):return np.prod(-np.partition(-data, k)[:k].astype(dfp.dtype))# now n > k and we have at least one positive elementap = np.argpartition(-np.absolute(data), k)low, high = ap[k:], ap[:k]# try multiplying the k with highest absolute valuegreedy = np.prod(dfp[high])if greedy >= 0:return greedy# there are two possible ways of fixing the sign:# either swap the worst negative inside for the best positive outside# or swap the worst positive inside for the best negative outside# compute both and compare# bpo in, wni outbpo = np.max(dfp[low])if bpo <= 0:spfn = 0else:neg_high = np.where(neg[high])[0]wni_ind = np.argmax(data[high[neg_high]])# translate to index in highwni_ind = neg_high[wni_ind]spfn = bpo*np.prod(dfp[high[:wni_ind]])*np.prod(dfp[high[wni_ind+1:]])# bno in, wno outpos_high = np.where(~neg[high])[0]if len(pos_high) == 0:snfp = 0else:wpi_ind = np.argmin(data[high[pos_high]])wpi_ind = pos_high[wpi_ind]bno = np.min(dfp[low])snfp = bno*np.prod(dfp[high[:wpi_ind]])*np.prod(dfp[high[wpi_ind+1:]])return max(spfn, snfp)

Brief description of algo:

  • special case k odd, all data negative find k least negative by partition, return prod, stop
  • partition by absolute value, splitting at rank k - O(n) worstcase with introselect library function
  • if prod top k >= 0, stop
  • if possible swap least positive inside for most negative outside, store prod
  • if possible swap least negative inside for most positive outside, store prod
  • return best of above, stop

Sample run:

>>> test_input = [[1,2,3,4,5,6,7,8],[1,-2,3,4,5,100,2,3,1],[-10,-10,1,3,2],[1000,7,-6,2,2]]
>>> for t in test_input:
...     kmp.kmaxprod(t,4)
... 
1680
6000
600
28000

Test script, thanks @Stefan Pochmann

import itertools, operator, functools, time
def naive(data, k):return max(functools.reduce(operator.mul, comb) for comb in itertools.combinations(data, k))test_input = [([1,2,3,4,5,6,7,8], 4), ([1,-2,3,4,5,100,2,3,1], 4),([-10,-10,1,3,2], 4), ([1000,7,-6,2,2],4),([-1, 0, 1], 2), ([2, 5, 8, 9, 1, 3, 7], 4),([-1, -1, 2, 1], 2), ([-1000, -1, 2, 3], 2),([3, 5, 2, 8, 3], 2), ([-1000, -1, 2, 3, 4, 5, 6, 7], 2)]for t, k in test_input:print(t, k, kmaxprod_v2(t, k), naive(t, k))ne = 0
t = np.zeros((3,))
import random
for k in range(2, 20):for n in range(k, 24):print('n =', n, ': k =', k, 'errors:', ne, 'total time O(n), naive:', np.diff(t))for _ in range(100):data = [random.randrange(-14, 15) for _ in range(n)]t[0] += time.time()a = kmaxprod_v2(data, k)t[1] += time.time()b = naive(data, k)t[2] += time.time()if a != b:ne += 1print(data, k, a, b)
https://en.xdnf.cn/q/117927.html

Related Q&A

Kivy error - Unable to get a window, abort

I installed kivy on my Raspberry pi3, where i run a python program that already works on another pi3.I now am trying to install the same thing on this second pi, and it doesnt work...maybe I forgot som…

Selenium 3.0.2 error with Firefox 50: executable may have wrong permissions

Im trying to use Selenium 3.0.2 with Firefox 50.0.1 in Windows 7. Ive followed the instructions in this post to setup correctly the driver and the paths but Im getting the following error: Traceback (m…

Convert a jpg to a list of lists

Im trying to figure out how to convert a jpg into a list of lists (using python 3.2.3) such that:[ [red,blue,red,etc..], #line1 [blue,red,yellow, etc...], #line2 [orange,yellow,black,et…

TypeError: No to_python (by-value) converter found for C++ type

Im trying to expose my C++ Classes to Python using Boost.Python. Here is a simplyfied version of what Im trying to do:struct Base {virtual ~Base() {};virtual char const *Hello() {printf("Base.Hell…

USB interface in Python

I have this (http://www.gesytec.de/en/download/easylon/p/16/) USB device connected to my Win7. I am just trying to read the vendor ID and product ID. I have Python 2.7.Here is the code,import usb busse…

Django M2M Through extra fields with multiple models

Im trying to figure out the best way to set up the following django model (genericised for security reasons).ThingA:User(M2M through "UserRelation")ThingB:User(M2M through "UserRelation&…

Openpyxl: Worksheet object has no attribute values

My goal is to read in an excel file and view the codes in a pandas dataframe (i.e. = A3) rather than the resulting values from excel executing the codes, which is the pandas default if read in using pa…

Calculation of Contact/Coordination number with Periodic Boundary Conditions

I have data for N atoms including the radius of each atom, the position of each atom and the box dimensions. I want to calculate the number of atoms each atom is in contact with and store the result. T…

how can I export multiple images using zipfile and urllib2

I am trying to add multiple image files into my zip. I have searched around and knows how to add a single one. I tried to loop through multiple images then write into it but it didnt work. I kind of d…

XPATH for Scrapy

So i am using SCRAPY to scrape off the books of a website. I have the crawler working and it crawls fine, but when it comes to cleaning the HTML using the select in XPATH it is kinda not working out ri…