Nehmen wir an, wir haben eine nicht negative Ganzzahl, die "heftig" (dh "schwer") ist, wenn ihr durchschnittlicher Ziffernwert größer als 7 ist.
Die Nummer 6959 ist "heftig", weil:
(6 + 9 + 5 + 9) / 4 = 7,5
Die Nummer 1234 ist nicht, weil:
(1 + 2 + 3 + 4) / 4 = 2,5
Schreiben Sie eine Funktion in einer beliebigen Sprache,
HeftyDecimalCount(a, b)
Wenn zwei positive ganze Zahlen a und b angegeben werden, wird eine ganze Zahl zurückgegeben, die angibt, wie viele "kräftige" ganze Zahlen sich innerhalb des Intervalls [a..b] einschließlich befinden.
Zum Beispiel mit a = 9480 und b = 9489:
9480 (9+4+8+0)/4 21/4 = 5.25
9481 (9+4+8+1)/4 22/4 = 5.5
9482 (9+4+8+2)/4 23/4 = 5.75
9483 (9+4+8+3)/4 24/4 = 6
9484 (9+4+8+4)/4 25/4 = 6.25
9485 (9+4+8+5)/4 26/4 = 6.5
9486 (9+4+8+6)/4 27/4 = 6.75
9487 (9+4+8+7)/4 28/4 = 7
9488 (9+4+8+8)/4 29/4 = 7.25 hefty
9489 (9+4+8+9)/4 30/4 = 7.5 hefty
Zwei der Zahlen in diesem Bereich sind "heftig" und daher sollte die Funktion 2 zurückgeben.
Einige Richtlinien:
- Nehmen Sie an, dass weder a noch b 200.000.000 überschreiten.
- Eine n-Quadrat-Lösung wird funktionieren, aber langsam sein - wie schnell können wir das lösen?
Antworten:
Das Problem kann in O (Polylog (b)) gelöst werden.
Wir definieren
f(d, n)
die Anzahl der Ganzzahlen mit bis zu d Dezimalstellen, wobei die Ziffernsumme kleiner oder gleich n ist. Es ist ersichtlich, dass diese Funktion durch die Formel gegeben istMit dieser Formel können wir zum Beispiel die Anzahl der schweren Zahlen im Intervall von 8000 bis 8999 ermitteln
1000 - f(3, 20)
, da sich in diesem Intervall tausend Zahlen befinden und wir die Anzahl der Zahlen mit einer Ziffernsumme von 28 oder weniger subtrahieren müssen Dabei wird berücksichtigt, dass die erste Ziffer bereits 8 zur Ziffernsumme beiträgt.Als komplexeres Beispiel betrachten wir die Anzahl der schweren Zahlen im Intervall 1234..5678. Wir können zuerst in Schritten von 1 von 1234 bis 1240 gehen. Dann gehen wir in Schritten von 10 von 1240 bis 1300. Die obige Formel gibt uns die Anzahl der schweren Zahlen in jedem solchen Intervall:
Jetzt gehen wir von 1300 bis 2000 in Schritten von 100:
Von 2000 bis 5000 in Schritten von 1000:
Jetzt müssen wir die Schrittweite wieder verringern, und zwar von 5000 auf 5600 in Schritten von 100, von 5600 auf 5670 in Schritten von 10 und schließlich von 5670 auf 5678 in Schritten von 1.
Ein Beispiel für eine Python-Implementierung (die inzwischen leicht optimiert und getestet wurde):
Bearbeiten : Ersetzt den Code durch eine optimierte Version (die noch hässlicher aussieht als der Originalcode). Außerdem wurden ein paar Eckfälle behoben, während ich dabei war.
heavy(1234, 100000000)
dauert ungefähr eine Millisekunde auf meiner Maschine.quelle
binomial()
Funktion. Es gibt noch ein paar Dinge, die leicht verbessert werden können. Ich werde in ein paar Minuten ein Update veröffentlichen.f(d, n)
nicht zweimal mit denselben Parametern während eines Programmlaufs aufgerufen.Rekurse und verwende Permutationen.
Angenommen, wir definieren eine allgemeine Funktion, die die Werte zwischen a und b mit einer Schwere von mehr als x findet:
Bei Ihrem Beispiel von a = 8675 bis b = 8689 ist die erste Ziffer 8, also werfen Sie sie weg - die Antwort ist die gleiche wie bei 675 bis 689 und erneut bei 75 bis 89.
Das Durchschnittsgewicht der ersten beiden Ziffern 86 beträgt 7, sodass die verbleibenden Ziffern ein Durchschnittsgewicht von mehr als 7 benötigen, um sich zu qualifizieren. Also der Anruf
ist äquivalent zu
Unser Bereich für die (neue) erste Ziffer ist also 7 bis 8, mit diesen Möglichkeiten:
Für 7 benötigen wir immer noch einen Durchschnitt von mehr als 7, der nur von einer letzten Ziffer von 8 oder 9 ausgehen kann, was uns 2 mögliche Werte gibt.
Für 8 benötigen wir einen Durchschnitt von mehr als 6, was nur von einer letzten Ziffer von 7-9 kommen kann, was uns 3 mögliche Werte gibt.
2 + 3 ergibt also 5 mögliche Werte.
Was passiert ist, dass der Algorithmus mit der 4-stelligen Zahl beginnt und diese in kleinere Probleme aufteilt. Die Funktion ruft sich bei einfacheren Versionen des Problems wiederholt auf, bis sie etwas hat, das sie handhaben kann.
quelle
Vielleicht können Sie viele Kandidaten im Intervall von a bis b überspringen, indem Sie ihre "Schwere" aufsummieren.
Wenn Sie die Länge Ihrer Zahl kennen, wissen Sie, dass jede Ziffer die Schwere nur um 1 / Länge verändern kann.
Wenn Sie also mit einer Zahl beginnen, die nicht schwer ist, sollten Sie in der Lage sein, die nächste Zahl zu berechnen, die schwer ist, wenn Sie sie um eins erhöhen.
In Ihrem obigen Beispiel, das mit 8680 avg = 5,5 beginnt, was 7-5,5 = 1,5 Punkte von Ihrer Schweregrenze entfernt ist, wissen Sie, dass sich 1,5 / (1/4) = 6 Zahlen dazwischen befinden, die NICHT schwer sind.
Das sollte zum Trick!
quelle
/length
s los .Wie wäre es mit einer einfachen rekursiven Funktion? Zur Vereinfachung werden alle großen Zahlen mit
digits
Ziffern und einer minimalen Ziffernsumme von berechnetmin_sum
.Implementierte dies in Python und fand alle 9-stelligen schweren Zahlen in ~ 2 Sekunden. Ein bisschen dynamisches Programmieren könnte dies verbessern.
quelle
Dies ist eine mögliche Lösung.
quelle
C, für Intervall [a, b] ist es O (ba)
//die Übung
//die Ergebnisse
quelle