Tarea de prueba Yandex

Desafío


Escriba una función que desde una matriz de entrada arbitraria seleccionará todas las combinaciones de números cuya suma sea 10.

A primera vista, la tarea es simple, todo lo que necesita hacer es escribir una recursión y ordenar todos los valores.

O puede usar un incremento binario, pero para iterar sobre todos los valores para un vector de números de longitud N, se necesitan 2 ^ n iteraciones.

Primero, elegimos un caso especial, supongamos que la matriz consiste en números> 0. Luego, en base a este ejemplo, implementaremos todos los casos.

PASO 1


a) Considere uno de los casos especiales: la suma de todos los elementos de la matriz <10.
La lógica es simple, suma (V) <10, luego suma (V) -V [i] <suma, es decir, si la suma de las combinaciones siempre será menor que 10.

b) Si suma (V) = 10, entonces la suma suma (V) -V [i] <suma. El resultado será solo un v .

PASO 2


Eliminamos todo lo innecesario del vector.

Como ejemplo, tome la matriz [13, 10, 20, 13, 13, 18, 2, 9, 5, 8, 8, 9, 2, 1, 8, 16, 4, 15, 2, 2, 2, 1, 5 , 5, 5].

Muestra de inmediato que no tiene sentido buscar combinaciones si el valor es> 10, pero todo se aclarará de inmediato. si lo clasificamos:

[1, 1, 2, 2, 2, 2, 2, 4, 5, 5, 5, 5, 8, 8, 8, 9, 9, 10, 13, 13, 13, 15, 16, 18, 20 ]

En esta etapa, ya podemos saber con certeza que necesitamos eliminar todos los elementos mayores de 10
v => [1, 1, 2, 2, 2, 2, 2, 4, 5, 5, 5, 5, 8, 8, 8, 9, 9, 10]

Pero, de hecho, todo es un poco más interesante. necesitamos limitar el vector al valor para que V [0] + V [i] <= 10; donde tiendo a N; Pero si V [i] = 10, entonces agregamos 10 al resultado
v => [1, 1, 2, 2, 2, 2, 2, 4, 5, 5, 5, 5, 8, 8, 8, 9, 9]

PASO 3


Hay elementos duplicados en una matriz ya filtrada. Si descomponemos el vector en sub-vectores y calculamos su suma, obtenemos algo como esto
[1,1] => 2
[2, 2, 2, 2, 2] => 10
[4] => 4
[5, 5, 5, 5] => 20
[8, 8, 8] => 24
[9,9] => 18

La esencia de mis pensamientos es tal que no tiene sentido considerar combinaciones de números repetidos si su número * valor> 10. Es decir, cortamos los vectores hasta que su suma sea menor que 10, y agreguemos los que son 10 al resultado:
[1,1] => [1,1]
[2, 2, 2, 2, 2] => [2, 2, 2, 2]
[4] => [4]
[5, 5, 5, 5] => [5]
[8, 8, 8] => [8]
[9,9] => [9]

Como resultado del tercer paso, nuestro vector será el siguiente
[1, 1, 2, 2, 2, 4, 5, 8, 9]

Como puede ver, el tamaño del vector ha disminuido de 25 a 9, es mucho más pequeño (recuerde el número de iteraciones);

Con números negativos


Esto es un poco más complicado. asumiremos que hemos implementado la función de encontrar combinaciones para un vector ordenado positivo basado en las restricciones anteriores.
comb (arr, sum), donde sum es la cantidad requerida, arr es un vector ordenado de números positivos

Por ejemplo, tome el vector:
[19, 15, -9, 3, -13, -8, -12, 11, -2, -10, 0, 7, 17, -17, -14, -15, -11, -6, -12 , -10, 9]

1. Romper el vector
A = solo valores positivos
B = solo valores negativos
Y también ver si tenemos valores = 0

2. Ordenar
Ordenar los vectores (positivo ascendente, negativo descendente)

Verifique el caso especial para números positivos (PASO 1)

3. Verificación de positivo
Verificar valores positivos
peine (B, 10)

3. Comprobar si hay negativo
crear combinaciones de todos los números negativos, pero con la restricción:

(suma de elementos módulo) <(suma de todos los positivos) + 10
encontramos combinaciones para las NUEVAS sumas de referencia (la suma de los elementos módulo + 10)

4. Igualdad 0
Si el vector fuente tiene un valor de 0, entonces agregamos todas las combinaciones + 0 al resultado;

Como resultado de tales limitaciones, en promedio, cuando se prueban valores con una matriz de 28 y 1000 pruebas de largo, la ganancia de tiempo es casi 42%

Tenga cuidado de no parecer nervioso. El autor no es responsable del sufrimiento moral.
function combine(arr, etalon = 10) { //--------------------------------------------// //------------- helpers --------------------// //    // Create binnary array function createBin(length) { let bin = []; for (let i = 0; i < length; i++) { bin[i] = false; } return bin; } //   1 //Binnary add 1 bit function binAddBit(bin, i = 0) { if (i >= bin.length) { return null; } if (bin[i] == false) { bin[i] = true; return bin; } else { bin[i] = false; i++; return binAddBit(bin, i); } } function iniq(arr) { let result = []; let object = {}; arr.forEach(vector => { value = vector.sort(function(a, b) { return a - b }); key = value.join(','); object[key] = value; }); for (var key in object) { result.push(object[key]); } return result; } //   // : //       //       //       function _combine(arr, sum = 10) { let result = []; //   if (arr[0] > sum) return []; if (arr[0] == sum) return [ [sum] ]; //1.   let $aKey = {}; let $a = []; let $sum = 0; //    $aKey[arr[0]] = arr[0]; $a.push(arr[0]); $sum += arr[0]; let $eqSum = false; for (let i = 1; i < arr.length; i++) { if ((arr[i] + arr[0]) <= sum) { //-----------------------------// // count*element < sum $aKey[arr[i]] = $aKey[arr[i]] != undefined ? $aKey[arr[i]] += arr[i] : arr[i]; if ($aKey[arr[i]] < sum) { $a.push(arr[i]); $sum += arr[i]; } //-----------------------------// //-----------------------------// // count*element = sum if ($aKey[arr[i]] === sum) { let $res = []; for (let j = 0; j < (sum / arr[i]); j++) { $res.push(arr[i]); } result.push($res); } //-----------------------------// } if (arr[i] == sum) { $eqSum = true; } } if ($eqSum) { result.push([sum]); } if ($sum < sum) return result; if ($sum == sum) { result.push($a); return result; } //   let bin = createBin($a.length); while (change = binAddBit(bin)) { let $sum = 0; let $comb = []; for (let i = 0; i < change.length; i++) { if (change[i] == false) continue; $sum += $a[i]; if ($sum > sum) break; // exit in accumulate $comb.push($a[i]); if ($sum == sum) { result.push($comb); } } } return result; } //------------- helpers --------------------// //--------------------------------------------// let result = []; //         //   -   let zero = false; //       let posetive = []; let negative = []; let sumPosetive = 0; arr.forEach(element => { if (element === 0) { zero = true; } if (element < 0) { negative.push(element); } if (element > 0) { posetive.push(element); sumPosetive += element; } }); //   ( ) posetive.sort(function(a, b) { return a - b }); negative.sort(function(a, b) { return b - a }); //       ,  //       if (sumPosetive < etalon) return []; //       if (sumPosetive == etalon) { result.push(posetive); if (zero) { let _clone = posetive.slice(); _clone.push(0); result.push(_clone); } return result; } //      ; result = result.concat(_combine(posetive, etalon)); // SUPPLE -          combinPosetiveLim negative = negative.filter(function(value) { return -value <= (sumPosetive + etalon); }); //    (  ) let bin = createBin(negative.length); //   while (changeBin = binAddBit(bin)) { let sum = etalon; let vector = []; //      for (let i = 0; i < changeBin.length; i++) { if (changeBin[i] == false) continue; sum -= negative[i]; vector.push(negative[i]); } if (sum > (sumPosetive + etalon)) continue; let lines = _combine(posetive, sum); lines.forEach(value => { result.push(vector.concat(value)); }); } //    0 if (zero) { result.forEach(item => { let _clone = item.slice(); _clone.push(0); result.push(_clone); }); } result = iniq(result); return result; } 

Source: https://habr.com/ru/post/460923/


All Articles