Máxima suma de elementos consecutivos
Definir la función
1 |
sumaMaxima :: [Integer] -> Integer |
tal que (sumaMaxima xs) es el valor máximo de la suma de elementos consecutivos de la lista xs. Por ejemplo,
1 2 3 4 5 6 7 |
sumaMaxima [] == 0 sumaMaxima [2,-2,3,-3,4] == 4 sumaMaxima [-1,-2,-3] == 0 sumaMaxima [2,-1,3,-2,3] == 5 sumaMaxima [1,-1,3,-2,4] == 5 sumaMaxima [2,-1,3,-2,4] == 6 sumaMaxima [1..10^6] == 500000500000 |
Comprobar con QuickCheck que
1 |
sumaMaxima xs == sumaMaxima (reverse xs) |
Soluciones
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
import Data.List (inits, tails) import Test.QuickCheck -- 1ª definición -- ============= sumaMaxima1 :: [Integer] -> Integer sumaMaxima1 [] = 0 sumaMaxima1 xs = maximum (0 : map sum [sublista xs i j | i <- [0..length xs - 1], j <- [i..length xs - 1]]) sublista :: [Integer] -> Int -> Int -> [Integer] sublista xs i j = [xs!!k | k <- [i..j]] -- 2ª definición -- ============= sumaMaxima2 :: [Integer] -> Integer sumaMaxima2 [] = 0 sumaMaxima2 xs = sumaMaximaAux 0 0 xs where m = maximum xs sumaMaximaAux :: Integer -> Integer -> [Integer] -> Integer sumaMaximaAux m v [] = max m v sumaMaximaAux m v (x:xs) | x >= 0 = sumaMaximaAux m (v+x) xs | v+x > 0 = sumaMaximaAux (max m v) (v+x) xs | otherwise = sumaMaximaAux (max m v) 0 xs -- 3ª definición -- ============= sumaMaxima3 :: [Integer] -> Integer sumaMaxima3 [] = 0 sumaMaxima3 xs = maximum (map sum (segmentos xs)) -- (segmentos xs) es la lista de los segmentos de xs. Por ejemplo -- segmentos "abc" == ["", "a","ab","abc","b","bc","c"] segmentos :: [a] -> [[a]] segmentos xs = [] : concat [tail (inits ys) | ys <- init (tails xs)] -- 4ª definición -- ============= sumaMaxima4 :: [Integer] -> Integer sumaMaxima4 [] = 0 sumaMaxima4 xs = maximum (concat [scanl (+) 0 ys | ys <- tails xs]) -- Comprobación -- ============ -- La propiedad es prop_sumaMaxima :: [Integer] -> Bool prop_sumaMaxima xs = sumaMaxima2 xs == n && sumaMaxima3 xs == n && sumaMaxima4 xs == n where n = sumaMaxima1 xs -- La comprobación es -- λ> quickCheck prop_sumaMaxima -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- λ> let n = 10^2 in sumaMaxima1 [-n..n] -- 5050 -- (2.10 secs, 390,399,104 bytes) -- λ> let n = 10^2 in sumaMaxima2 [-n..n] -- 5050 -- (0.02 secs, 0 bytes) -- λ> let n = 10^2 in sumaMaxima3 [-n..n] -- 5050 -- (0.27 secs, 147,705,184 bytes) -- λ> let n = 10^2 in sumaMaxima4 [-n..n] -- 5050 -- (0.04 secs, 11,582,520 bytes) prop_inversa :: [Integer] -> Bool prop_inversa xs = sumaMaxima2 xs == sumaMaxima2 (reverse xs) |
Falla con
sumaMaxima [-1, -2, -3, 100]
Versión en Maxima, con un bucle «for»