Descomponer un valor como una suma de números cuadrados -- f# campo con combinatorics camp codereview Relacionados El problema

Decompose a value as a sum of square numbers


3
vote

problema

Español

Mi hija tenía una pregunta sobre la tarea de su matemáticas que era escribir un valor como una suma de 4 o menos números cuadrados.

Por ejemplo, X = 73 podría ser 36 + 36 + 1.

Se me ocurrió un algoritmo de fuerza realmente bruta que muestra todas las combinaciones, pero cuando los valores superan los 1000, se vuelve bastante lento.

¿Hay una forma inteligente de lograr esto? Aquí está mi Algo en F #

  let squares = [ 0.. 100 ] |> Seq.map (fun x -> x * x) |> Seq.toList  let rec calc total attempts squares accu results =   match (total, attempts, squares) with   | (0, _, _) -> accu :: results   | (_, 0, _) -> [] :: results   | (x, _, _) when x < 0 -> [] :: results   | (_, _, []) -> [] :: results   | total, attempts, squares ->     let filteredSquares = squares |> Seq.filter ((>=) total )     filteredSquares        |> Seq.collect(fun sq ->                            calc (total - sq)                                (attempts - 1)                                (filteredSquares |> Seq.toList)                                (sq :: accu)                                results) |> Seq.toList  let res =    calc 8058 4 squares [] []    |> Seq.filter(fun lst -> lst <> [])   |> Seq.sortBy (fun lst -> lst.Length)   |> Seq.take 1   |> Seq.toList    

Los comentarios adicionales sobre el mejor código F # serían apreciados también. Una cosa que me estaba preguntando fue si podría hacerlo perezoso usando secuencias.

Original en ingles

My daughter had a question on her maths homework which was to write a value as a sum of 4 or fewer square numbers.

For example, x = 73 could be 36 + 36 + 1.

I came up with a really brute force algorithm that shows all combinations but when the values get above 1000 it becomes quite slow.

Is there a clever way of achieving this? Here is my algo in F#

let squares = [ 0.. 100 ] |> Seq.map (fun x -> x * x) |> Seq.toList  let rec calc total attempts squares accu results =   match (total, attempts, squares) with   | (0, _, _) -> accu :: results   | (_, 0, _) -> [] :: results   | (x, _, _) when x < 0 -> [] :: results   | (_, _, []) -> [] :: results   | total, attempts, squares ->     let filteredSquares = squares |> Seq.filter ((>=) total )     filteredSquares        |> Seq.collect(fun sq ->                            calc (total - sq)                                (attempts - 1)                                (filteredSquares |> Seq.toList)                                (sq :: accu)                                results) |> Seq.toList  let res =    calc 8058 4 squares [] []    |> Seq.filter(fun lst -> lst <> [])   |> Seq.sortBy (fun lst -> lst.Length)   |> Seq.take 1   |> Seq.toList  

Additional comments on better F# code would be appreciated as well. One thing I was wondering was whether I could make it lazy using sequences.

     
     
     

Lista de respuestas

1
 
vote
vote
La mejor respuesta
 
  let squares = [ 0.. 100 ] |> Seq.map (fun x -> x * x) |> Seq.toList   

No creo que limitar los cuadrados de esta manera es una buena idea. En su lugar, si lo movió dentro calc , podría escribirlo como:

  let squares =     Seq.initInfinite id     |> Seq.map (fun x -> x * x)     |> Seq.takeWhile (fun x -> x <= total)     |> Seq.toList   

calc5 es un nombre bastante malo: no dice nada sobre lo que calcula la función.


Si se limita a regresar siempre solo la suma más corta, la firma del método podría simplificarse bastante: puede deshacerse de attempts , 9988776655544337 y results . Esto también simplificaría un poco la implementación.

E incluso si no hace eso, creo que se debe realizar la filtración de listas vacías dentro de calc , no afuera.


Si simplifica la firma, puede aplicar Memoization para hacer el El cómputo mucho más rápido. La memoización ayudará aquí, porque lo que está desacelerando, el cálculo está calculando el resultado para el mismo background-color0 una y otra vez.

La implementación podría verse así:

  background-color1  

Esto calculará el resultado para valores alrededor de 10.000 de inmediato, pero 100.000 tarda unos segundos, por lo que es probable que haya una forma más eficiente de implementar esto.


Sin embargo, si está de acuerdo con encontrar algo de descomposición con la mayoría de la longitud dada, no necesariamente el más corto, tener el parámetro 9988777655555443312 tiene sentido y hace que el cálculo sea mucho más rápido cuando la descomposición es posible. (Por ejemplo, background-color3 Devoluciones inmediatamente con background-color4 , mientras que 99887766555443315 toma unos segundos para volver con una respuesta negativa).

El código:

  background-color6  
 
let squares = [ 0.. 100 ] |> Seq.map (fun x -> x * x) |> Seq.toList 

I don't think limiting the squares this way is a good idea. Instead, if you moved it inside calc, you could write it as:

let squares =     Seq.initInfinite id     |> Seq.map (fun x -> x * x)     |> Seq.takeWhile (fun x -> x <= total)     |> Seq.toList 

calc is a pretty bad name: it doesn't say anything about what the function calculates.


If you limit yourself to returning always only the shortest sum, the signature of the method could be simplified quite a lot: you could get rid of attempts, accu and results. This would also somewhat simplify the implementation.

And even if you don't do that, I think that filtering out empty lists should be done inside calc, not outside.


If you simplify the signature, you could then apply memoization to make the computation much faster. Memoization will help here, because what's slowing down the computation is calculating the result for the same total over and over.

The implementation could look like this:

let rec calculateSquaresSum =     let calculateSquaresSum' total =         if total = 0 then             []         else             let squares =                 Seq.initInfinite (fun x -> x + 1)                 |> Seq.map (fun x -> x * x)                 |> Seq.takeWhile (fun x -> x <= total)                 |> Seq.toList                 |> List.rev              squares             |> Seq.map (fun sq -> sq :: (calculateSquaresSum (total - sq)))             |> Seq.minBy (fun sum -> sum.Length)      memoize calculateSquaresSum' 

This will calculate the result for values around 10.000 immediately, but 100.000 takes a few seconds, so there likely is a more efficient way to implement this.


Though if you're okay with finding just some decomposition with at most the given length, not necessarily the shortest one, having the attempts parameter makes sense and makes the computation much faster when the decomposition is possible. (E.g. calculateSquaresSum(1000000 - 1, 4) returns immediately with [998001; 1849; 100; 49], while calculateSquaresSum(100000 - 1, 3) takes few seconds to return with a negative answer.)

The code:

let rec calculateSquaresSum =     let calculateSquaresSum' (total, attempts) =         if total = 0 then             Some []         elif attempts = 0 then             None         else             let squares =                 Seq.initInfinite (fun x -> x + 1)                 |> Seq.map (fun x -> x * x)                 |> Seq.takeWhile (fun x -> x <= total)                 |> Seq.toList                 |> List.rev              squares             |> Seq.map (fun sq ->                 match calculateSquaresSum (total - sq, attempts - 1) with                 | None -> None                 | Some tail -> Some (sq::tail))             |> Seq.tryPick id      memoize calculateSquaresSum' 
 
 
   
   

Relacionados problema

15  Cracker de contraseña de fuerza bruta  ( Brute force password cracker ) 
Escribí este script para una prueba de concepto JavaScript Password Cracker: var charset = " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_...

4  Permodificar codility  ( Permcheck codility ) 
El siguiente código obtiene un 100% en el Permdeck tarea en la CODILIDAD . Debe ser O (n). La pregunta es: Se da una matriz no vacía que consta de n ent...

3  Encuentra todas las combinaciones distintas de letras en una cadena  ( Find all distinct combinations of letters in a string ) 
Me he estado preparando para las entrevistas y recogiendo moderno C ++. Una pregunta reciente que hice fue encontrar todas las combinaciones (o subconjuntos d...

3  Mi implementación de permutación lexicográfica en F # es 3x más lenta que C #  ( My implementation of lexicographic permutation in f is 3x slower than c ) 
¿Puede alguien ayudarme con la siguiente micro optimización para el código F # para la permutación lexicográfica? Tengo código en C # que se ejecuta para 0,...

7  Generar un diccionario de contraseñas  ( Generate a dictionary of passwords ) 
Tengo un script de Python que genera un diccionario de todas las combinaciones de contraseña posibles de 3 dígitos. Esencialmente funciona solo en la anidació...

1  Imprima todos los tamaños posibles de subsecuencias de cadena en C  ( Print out all possible sizes of subsequences of string in c ) 
Por ejemplo, dada una cadena "abcdefghijk", quiero que mi función se imprima: a, b, c, d, e, f, g, h, i, j, k. ab, bc, cd, de, ef, fg, gh, hi, ij, jk ab...

1  Encuentra triángulos de la línea  ( Find triangles from line ) 
Tengo algunas líneas que forman triángulos. Me gustaría desafiar la forma más rápida de encontrar todos los triángulos. En particular, el código debe tom...

1  Encuentra la frecuencia de combinaciones en un gran conjunto de datos  ( Find frequency of combinations in large data set ) 
Mi preocupación es el rendimiento del Código. Se tarda mucho más de lo que me gustaría. Estaría dispuesto a renunciar a un poco de memoria para un mayor rendi...

1  Reto de primos consecutivos en Codeeeval.com  ( Consecutive primes challenge at codeeval com ) 
Estoy trabajando a través de un nuevo desafío en Codeeeval.com y creo que estoy obteniendo un resultado correcto, pero no puedo pasar por su alumnador. No est...

10  Función recursiva que genera las permutaciones de una cadena  ( Recursive function that generates the permutations of a string ) 
Estoy buscando una revisión de mi función recursiva que genere las permutaciones de una cadena. ¿Hay mejores formas de hacer esto? var permutations = []; ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos