Yandex-Testaufgabe

Herausforderung


Schreiben Sie eine Funktion, die aus einem beliebigen Eingabearray alle Zahlenkombinationen mit einer Summe von 10 auswählt.

Auf den ersten Blick ist die Aufgabe einfach. Sie müssen lediglich eine Rekursion schreiben und alle Werte sortieren.

Sie können auch ein binäres Inkrement verwenden. Um jedoch alle Werte für einen Vektor mit Zahlen der Länge N zu durchlaufen, sind 2 ^ n Iterationen erforderlich.

Zuerst wählen wir einen Sonderfall aus, nehmen wir an, dass das Array aus Zahlen> 0 besteht. Später werden wir anhand dieses Beispiels alle Fälle implementieren.

SCHRITT 1


a) Betrachten Sie einen der Sonderfälle - die Summe aller Elemente des Arrays <10.
Die Logik ist einfach: Summe (V) <10, dann Summe (V) -V [i] <Summe, dh wenn die Summe der Kombinationen immer kleiner als 10 ist.

b) Wenn Summe (V) = 10 ist, dann ist die Summe Summe (V) -V [i] <Summe. Das Ergebnis ist nur eine v .

SCHRITT 2


Wir entfernen alles Unnötige aus dem Vektor

Nehmen Sie als Beispiel das Array [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].

Es zeigt sofort, dass es keinen Sinn macht, nach Kombinationen zu suchen, wenn der Wert> 10 ist, aber alles wird sofort klar. wenn wir es sortieren:

[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 ]]

Zu diesem Zeitpunkt können wir bereits sicher sein, dass wir alle Elemente löschen müssen, die größer als 10 sind
v => [1, 1, 2, 2, 2, 2, 2, 4, 5, 5, 5, 5, 8, 8, 8, 9, 9, 10]

Tatsächlich ist aber alles etwas interessanter. wir müssen den Vektor auf den Wert begrenzen, so dass V [0] + V [i] <= 10; wo ich zu N neige; Wenn jedoch V [i] = 10 ist, addieren wir 10 zum Ergebnis
v => [1, 1, 2, 2, 2, 2, 2, 4, 5, 5, 5, 5, 8, 8, 8, 9, 9]

SCHRITT 3


In einem bereits gefilterten Array befinden sich doppelte Elemente. Wenn wir den Vektor in Untervektoren zerlegen und ihre Summe berechnen, erhalten wir so etwas
[1,1] => 2
[2, 2, 2, 2, 2] => 10
[4] => 4
[5, 5, 5, 5] => 20
[8, 8, 8] => 24
[9.9] => 18

Das Wesentliche meiner Gedanken ist, dass es keinen Sinn macht, Kombinationen sich wiederholender Zahlen zu berücksichtigen, wenn ihre Zahl *> 10 ist. Das heißt, wir schneiden die Vektoren ab, bis ihre Summe kleiner als 10 ist, und addieren diejenigen, die 10 sind, zum Ergebnis:
[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]

Als Ergebnis des dritten Schritts wird unser Vektor wie folgt sein
[1, 1, 2, 2, 2, 4, 5, 8, 9]

Wie Sie sehen können, hat sich die Größe des Vektors von 25 auf 9 verringert und ist viel kleiner (denken Sie an die Anzahl der Iterationen).

Mit negativen Zahlen


Das ist etwas komplizierter. Wir gehen davon aus, dass wir die Funktion zum Finden von Kombinationen für einen positiv sortierten Vektor basierend auf den vorherigen Einschränkungen implementiert haben.
Kamm (arr, Summe), wobei Summe der erforderliche Betrag ist, ist arr ein Vektor, der aus positiven Zahlen sortiert ist

Nehmen Sie zum Beispiel den Vektor:
[19, 15, -9, 3, -13, -8, -12, 11, -2, -10, 0, 7, 17, -17, -14, -15, -11, -6, -12 , -10, 9]

1. Brechen Sie den Vektor
A = nur positive Werte
B = nur negative Werte
Und sehen Sie auch, ob wir Werte = 0 haben

2. Sortieren
Sortieren Sie die Vektoren (positiv aufsteigend, negativ absteigend)

Überprüfen Sie den Sonderfall auf positive Zahlen (SCHRITT 1)

3. Überprüfung des Positiven
Auf positive Werte prüfen
Kamm (B, 10)

3. Auf Negativ prüfen
Erstellen Sie Kombinationen aller negativen Zahlen, jedoch mit der Einschränkung:

(Summe der Elemente modulo) <(Summe aller positiven) + 10
wir finden Kombinationen für die NEUEN Referenzsummen (die Summe der Elemente modulo + 10)

4. Gleichheit 0
Wenn der Quellvektor den Wert 0 hat, addieren wir alle Kombinationen + 0 zum Ergebnis.

Infolge solcher Einschränkungen beträgt der Zeitgewinn beim Testen von Werten mit einem Array von 28 und 1000 Tests im Durchschnitt fast 42%

Achten Sie darauf, nicht nervös auszusehen. Der Autor ist nicht verantwortlich für moralisches Leiden.
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/de460923/


All Articles