Perfect Number
Ein echter Teiler von n ist ein positiver Teiler, der kleiner als n selbst ist. Eine vollkommene Zahl ist gleich der Summe ihrer echten Teiler: 6 = 1 + 2 + 3. Du erhältst eine positive ganze Zahl n. Gib true zurück, wenn n vollkommen ist, andernfalls false.
Funktion
- ninteger
- die positive Ganzzahl, die getestet werden soll
- Gibt zurückboolean
- wahr, wenn n der Summe seiner echten Teiler entspricht, andernfalls falsch
Einschränkungen
1 ≤ n ≤ 108
Beispiele
- Eingabe
- n = 28
- Ausgabe
- true
- Erklärung
- Die echten Teiler von
28sind1,2,4,7und14. Sie ergeben zusammen28, also ist28vollkommen.
- Eingabe
- n = 12
- Ausgabe
- false
- Erklärung
- Die echten Teiler von
12sind1,2,3,4und6. Sie ergeben zusammen16, was12übersteigt.
- Eingabe
- n = 1
- Ausgabe
- false
- Erklärung
1hat überhaupt keinen echten Teiler, daher ist die Summe0und nicht1.
+16 versteckte Tests beim Einreichen
Weiterführende Frage
Jede gerade vollkommene Zahl hat die Form 2^(p-1) × (2^p-1), wobei 2^p-1 prim ist. Kannst du mit dieser Formel alle vollkommenen Zahlen unterhalb von 10^8 auflisten, ohne jede Zahl zu testen?
Tipps
Öffne sie nacheinander. Jeder verrät ein bisschen mehr.
Schreibe die echten Teiler von
28auf. Welche davon würdest du finden, wenn du nur Zahlen bis5betrachten würdest?Teiler treten paarweise auf: Wenn
dein Teiler vonnist, dann auchn / d. Ein Element jedes Paares ist höchstens√n.Setze die Summe auf
1, gib fürn == 1falsezurück und durchlaufedab2, solanged * d ≤ ngilt. Addieredundn / d, aber nur einmal, wenn sie gleich sind.
Lösung
Die Definition verlangt eine Summe von Teilern, und eine naheliegende Schleife probiert jeden möglichen Kandidaten bis n / 2 aus. Für n = 10^8 sind das 5 × 10^7 Divisionen. Teiler treten paarweise auf und multiplizieren sich zu n, sodass du beide Mitglieder jedes Paars sammeln kannst, während du nur bis √n suchst – etwa 10^4 Schritte.
Alle echten Teiler addieren
Korrekt, wird aber bei den größten Tests nicht fertig
Idee
Folge der Definition. Probiere jedes d ab 1 aufwärts aus und addiere, wenn n % d == 0 gilt, d zu einer laufenden Summe. Vergleiche am Ende die Summe mit n. Bei 28 nimmt die Schleife 1, 2, 4, 7 und 14 auf, und 1 + 2 + 4 + 7 + 14 = 28.
Du kannst bei n / 2 aufhören. Ein Teiler außer n ergibt einen Quotienten von mindestens 2 und ist daher nie größer als die Hälfte von n. Die Grenze gilt auch für n = 1: Die Schleife wird nullmal ausgeführt, die Summe bleibt 0, und das Ergebnis ist false.
Die Halbierung des Bereichs ändert das Wachstum nicht. Für n = 10^8 wird die Schleife weiterhin 5 × 10^7 Mal ausgeführt, und zwar bei jeder Eingabe dieser Größe, unabhängig davon, ob sie einen Teiler hat oder nicht.
Algorithmus
- Setze
totalauf0. - Durchlaufe
dvon1bisn / 2. - Wenn
n % d == 0, addieredzutotal. - Gib zurück, ob
total == n.
def isPerfect(n):
total = 0
# No proper divisor of n is larger than n / 2.
for d in range(1, n // 2 + 1):
if n % d == 0:
total += d
return total == nFaktorenpaare bis zur Quadratwurzel sammeln
Idee
Wenn d n teilt, dann teilt auch n / d n. Für 28 sind die Paare 1 × 28, 2 × 14 und 4 × 7. In jedem Paar ist ein Element höchstens √n, denn zwei Zahlen, die größer als √n sind, ergeben multipliziert mehr als n. Eine Suche bis √n trifft also jedes Paar genau einmal, und du addierst dabei jeweils beide Elemente.
Bei zwei Elementen ist Vorsicht geboten. Das Paar 1 × n bringt n selbst ins Spiel, das kein echter Teiler ist: Beginne die Summe bei 1 und die Suche bei 2. Für n = 1 ist dieser Start jedoch falsch, denn der einzige Teiler ist die Zahl selbst. Gib deshalb vorher false zurück. Und wenn n eine Quadratzahl ist, wird die Wurzel mit sich selbst gepaart: Bei 36 muss 6 × 6 einmal 6 addieren, nicht zweimal.
Schreibe die Grenze als d * d ≤ n, sodass nur mit ganzen Zahlen gerechnet wird. Für n = 10^8 endet die Schleife bei d = 10^4; sie läuft also etwa 10^4 Mal statt 5 × 10^7 Mal.
Algorithmus
- Wenn
n == 1, gibfalsezurück. - Setze
totalauf1unddauf2. - Solange
d * d ≤ ngilt: Wenndein Teiler vonnist, addieredund außerdemn / d, wenn dieser Wert vondabweicht. - Gehe zum nächsten
d. - Gib zurück, ob
total == ngilt.
def isPerfect(n):
if n == 1:
return False
total = 1 # 1 divides every n > 1; n itself does not count
d = 2
while d * d <= n:
if n % d == 0:
total += d
partner = n // d
if partner != d: # a square root pairs with itself: add it once
total += partner
d += 1
return total == n
Stolperfallen und Grenzfälle
Der Paar-Trick ist kurz, und jeder seiner Fehler ändert die Summe um genau einen Teiler.
nselbst mitzählen. Das Paar1 × naddiertn, und dann scheint jede Zahl eine Summe größer alsnzu haben. Beginne die Gesamtsumme bei1und die Suche bei2.1als vollkommen bezeichnen. Wenn die Gesamtsumme bei1beginnt, ergibt der Vergleich für die Eingabe11 == 1. Die Summe ihrer echten Teiler ist0, also behandle sie vor der Schleife.- Eine Quadratwurzel zweimal addieren. Für
16sind die echten Teiler1,2,4und8, deren Summe15ergibt. Addiert man4zweimal, erhält man19. - Bei
d * d < naufhören. Dadurch wird die Quadratwurzel vollständig übersprungen, sodass4bei16nie gezählt wird. - Die Grenze aus einer Gleitkomma-Quadratwurzel ableiten. Bei einfacher Genauigkeit oder oberhalb von
2^53bei doppelter Genauigkeit kann die Wurzel einer Quadratzahl um eins zu klein ausfallen und einen Teiler auslassen. Der Testd * d ≤ nbleibt bei ganzen Zahlen und hat dieses Problem nie.
Häufige Fragen4
Wie hoch ist die Zeitkomplexität beim Überprüfen, ob eine Zahl eine vollkommene Zahl ist?
Das Sammeln von Teilerpaaren bis √n benötigt O(√n) Zeit und O(1) Speicherplatz. Für n = 10^8 sind das etwa 10^4 Schritte. Das Testen jedes Kandidaten bis n / 2 hat eine Komplexität von O(n) und benötigt bei derselben Eingabe etwa 5 × 10^7 Schritte.
Wie viele vollkommene Zahlen gibt es unter 10^8?
Fünf: 6, 28, 496, 8128 und 33550336. Sie werden schnell rar. Die nächste Zahl, 8589869056, passt nicht einmal in eine 32-Bit-Ganzzahl.
Gibt es ungerade vollkommene Zahlen?
Niemand weiß es. Jede bislang gefundene vollkommene Zahl ist gerade. Bei Suchen wurden ungerade vollkommene Zahlen unter 10^1500 ausgeschlossen, aber kein Beweis besagt, dass sie nicht existieren können. Deine Funktion muss anhand der Definition arbeiten und darf nicht einfach annehmen, dass die Eingabe gerade ist.
Was ist der Unterschied zwischen vollkommenen, überreichlichen und defizienten Zahlen?
Vergleiche die Summe der echten Teiler mit der Zahl. Sind sie gleich, ist die Zahl vollkommen, wie 28. Ist die Summe größer, ist die Zahl abundant, wie 12, dessen Teiler sich zu 16 addieren. Ist die Summe kleiner, ist die Zahl defizient, wie jede Primzahl, deren einziger echter Teiler 1 ist.
Ähnliche Aufgaben
Aufgaben mit denselben Ideen. Wer zwei oder drei davon löst, behält das Muster.
Python
def isPerfect(n):
# Schreibe hier den CodeFall 1
Fall 2
Fall 3
Eingabe
n = 28
Erwartet
true