Sucesión de suma de cuadrados de los dígitos
Definir la función
sucSumaCuadradosDigitos :: Integer -> [Integer]
tal que (sucSumaCuadradosDigitos n) es la sucesión cuyo primer término es n y los restantes se obtienen sumando los cuadrados de los dígitos de su término anterior. Por ejemplo,
λ> take 20 (sucSumaCuadradosDigitos 2016) [2016,41,17,50,25,29,85,89,145,42,20,4,16,37,58,89,145,42,20,4] λ> take 20 (sucSumaCuadradosDigitos 1976) [1976,167,86,100,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] λ> sucSumaCuadradosDigitos 2016 !! (10^8) 145
Soluciones
-- 1ª definición -- ============= sucSumaCuadradosDigitos1 :: Integer -> [Integer] sucSumaCuadradosDigitos1 n = iterate sumaCuadradosDigitos n -- --------------------------------------------------------------------- -- (sumaCuadradosDigitos n) es la suma de los cuadrados de los dígitos -- de n. Por ejemplo, -- sumaCuadradosDigitos 2016 == 41 sumaCuadradosDigitos :: Integer -> Integer sumaCuadradosDigitos n = sum (map (^2) (digitos n)) -- (digitos n) es la lista de los dígitos de n. Por ejemplo, -- digitos 325 == [3,2,5] digitos :: Integer -> [Integer] digitos n = [read [d] | d <- show n] -- 2ª definición -- ============= sucSumaCuadradosDigitos2 :: Integer -> [Integer] sucSumaCuadradosDigitos2 n = n : [sumaCuadradosDigitos x | x <- sucSumaCuadradosDigitos2 n] -- 3ª definición -- ============= -- A partir de los cálculos con las definiciones anteriores, se observa -- que para todo n (sucSumaCuadradosDigitos n) tiene una parte pura y -- otra periódica. Por ejemplo, para n = 2016, -- λ> take 20 (sucSumaCuadradosDigitos 2016) -- [2016,41,17,50,25,29,85,89,145,42,20,4,16,37,58,89,145,42,20,4] -- la parte pura es -- [2016,41,17,50,25,29,85] -- y la parte periódica es -- [89,145,42,20,4,16,37,58]) sucSumaCuadradosDigitos3 :: Integer -> [Integer] sucSumaCuadradosDigitos3 n = xs ++ cycle ys where (xs,ys) = sucCompactaSumaCuadradosDigitos n -- (sucCompactaSumaCuadradosDigitos n) es el par formado por la parte -- pura y la periódica de (sucSumaCuadradosDigitos n). Por ejemplo, -- λ> sucCompactaSumaCuadradosDigitos 2016 -- ([2016,41,17,50,25,29,85],[89,145,42,20,4,16,37,58]) -- λ> sucCompactaSumaCuadradosDigitos 1976 -- ([1976,167,86,100],[1]) sucCompactaSumaCuadradosDigitos :: Integer -> ([Integer],[Integer]) sucCompactaSumaCuadradosDigitos = partePuraPeriodica . sucSumaCuadradosDigitos1 -- (partePuraPeriodica xs) es el par formado por la parte pura y la -- periódica de xs. Por ejemplo, -- λ> partePuraPeriodica (sucSumaCuadradosDigitos 2016) -- ([2016,41,17,50,25,29,85],[89,145,42,20,4,16,37,58]) -- λ> partePuraPeriodica (sucSumaCuadradosDigitos 1976) -- ([1976,167,86,100],[1]) partePuraPeriodica :: [Integer] -> ([Integer],[Integer]) partePuraPeriodica xs = aux [] xs where aux as (b:bs) | elem b as = span (/=b) (reverse as) | otherwise = aux (b:as) bs -- Comparación de eficiencia -- ========================= -- λ> sucSumaCuadradosDigitos1 2016 !! (10^5) -- 145 -- (4.13 secs, 1,568,615,040 bytes) -- λ> sucSumaCuadradosDigitos2 2016 !! (10^5) -- 145 -- (0.04 secs, 16,620,344 bytes) -- λ> sucSumaCuadradosDigitos3 2016 !! (10^5) -- 145 -- (0.01 secs, 0 bytes) -- -- λ> sucSumaCuadradosDigitos2 2016 !! (10^8) -- 145 -- (24.54 secs, 15,998,659,480 bytes) -- λ> sucSumaCuadradosDigitos3 2016 !! (10^8) -- 145 -- (0.01 secs, 0 bytes)