Here, something is not optimal in Haskell, which (as in many of my ideas) is likely to be even more optimized. This happens something like this:
- Array sorting (I have interesting results, trying both ascending and descending)
- BN = first N elements of the array
- B (i), for i> N = the best candidate; where (assuming integers), if they are less than 1, the candidates are compared by the absolute value of their sums; if they are equal to 1 or more, by their sum; and if only one candidate is greater than 0, then that candidate is selected. If the candidateโs sum is 1, return that candidate as an answer. The candidates are:
B (i-1), B (i-1) [2,3,4..N] ++ array [i], B (i-1) [1,3,4..N] ++ array [ i] ... B (i-1) [1,2..N-1] ++ array [i]
B (i-2) [2,3,4..N] ++ array [i], B (i-2) [1,3,4..N] ++ [i] ... B (i -2) [1,2..N-1] ++ array [i]
...
B (N) [2,3,4..N] ++ array [i], B (N) [1,3,4..N] ++ array [i] ... B (N) [1 , 2..N-1] ++ array [i]
Note that for the part of the array where the numbers are negative (in the case of ascending sorting) or positive (in the case of descending sorting), step 3 can be performed immediately without calculation.
Output:
*Main> least 5 "desc" [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200] (10,[-1000,600,300,100,10]) (0.02 secs, 1106836 bytes) *Main> least 5 "asc" [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200] (50,[300,100,-200,-100,-50]) (0.02 secs, 1097492 bytes) *Main> main -- 10000 random numbers ranging from -100000 to 100000 (1,[-106,4,-40,74,69]) (1.77 secs, 108964888 bytes)
code:
import Data.Map (fromList, insert, (!)) import Data.List (minimumBy,tails,sort) import Control.Monad.Random hiding (fromList) array = [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200] least n rev arr = comb (fromList listStart) [fst (last listStart) + 1..m] where m = length arr r = if rev == "asc" then False else True sorted = (if r then reverse else id) (sort arr) listStart = if null lStart then [(n,(sum $ take n sorted,take n sorted))] else lStart lStart = zip [n..] . takeWhile (all (if r then (>0) else (<0)) . snd) . foldr (\ab -> let c = take n (drop a sorted) in (sum c,c) : b) [] $ [0..] s = fromList (zip [1..] sorted) comb list [] = list ! m comb list (i:is) | fst (list ! (i-1)) == 1 = list ! (i-1) | otherwise = comb updatedMap is where updatedMap = insert i bestCandidate list bestCandidate = comb' (list!(i - 1)) [i - 1,i - 2..n] where comb' best [] = best comb' best (j:js) | fst best == 1 = best | otherwise = let s' = map (\x -> (sum x,x)) . (take n . map (take (n - 1)) . tails . cycle) $ snd (list!j) t = s!i candidate = minimumBy compare' (map (add t) s') in comb' (minimumBy compare' [candidate,best]) js add x y@ (a,b) = (x + a,x:b) compare' a@ (a',_) b@ (b',_) | a' < 1 = if b' < 1 then compare (abs a') (abs b') else GT | otherwise = if b' < 1 then LT else compare a' b' rnd :: (RandomGen g) => Rand g Int rnd = getRandomR (-100000,100000) main = do values <- evalRandIO (sequence (replicate (10000) rnd)) putStrLn (show $ least 5 "desc" values)