Codewars Lösung | #1 Sequences: Pure Even Digit Perfect Squares (P.E.D.P.S)


coden
Codewars. Achieve mastery through challenge.
Daniel Kaser|1. November 2024
4 min.

Inhalt

  1. Die Fakten
  2. Beschreibung
  3. Lösung
    1. Pseudo-Code
    2. Code
  4. Feedback

Die Fakten:

Plattform:codewars.com
Name:#1 Sequences: Pure Even Digit Perfect Squares (P.E.D.P.S)
Level:6 kyu
Sprache:TypeScript

Beschreibung:

The integer 64 is the first integer that has all of its digits even and furthermore, is a perfect square.

The second one is 400 and the third one 484.

Give the numbers of this sequence that are in the range [a,b] (both values inclusive)

Examples:

Even digit squares between 100 to 1000:  [400, 484]  (the output should be sorted)
Even digit squares between 1000 to 4000: []

Features of the random tests:

number of tests = 167
maximum value for a = 1e10
maximum value for b = 1e12

You do not have to check the entries; a and b are always positive integers and a < b.

Happy coding!!

Quelle: codewars.com

Lösung

Pseudo-Code

Wie immer gibt's reichlich Varianten, hier ist eine meiner.

Erst die Lösungsschritte in Pseudo-Code. Los geht’s:

Lösungsschritte
Schritt 1

Da die Zahlen irgendwann ziemlich groß werden, können wir uns zuerst überlegen, was wir tun können um das Ganze effektiver zu machen und nicht durch jede einzelne Zahl der Range loopen zu müssen.

Schritt 2

Richtig! Wir loopen nur von der Wurzel der Start-Zahl bis zur Wurzel der End-Zahl.

Schritt 3

Wenn die jeweils aktuelle Zahl nicht gerade ist, können wir sie direkt überspringen.

Schritt 4

Ansonsten multiplizieren wir sie mit sich selbst und loopen durch die Ziffern dieses Quadrats.

Schritt 5

Wenn eine Ziffer nicht gerade ist, kann es kein P.E.D.P.S. mehr sein und wir können direkt die komplette aktuelle Zahl überspringen und die nächste testen.

Schritt 6

Wenn alle Ziffern gerade sind, können wir das aktuelle Quadrat an ein Ergebnis-Array anhängen.

Schritt 7

Nach dem äußeren Loop können wir dann das Ergebnis zurückgeben.

Code

Geil. Übersetzen wir unseren Pseudo-Code in TypeScript:

Lösungsschritte
Da wir mehrmals prüfen, ob eine Zahl gerade ist, erstelle ich mir schnell eine kleine Hilfsfunktion:
function isEven(num: number): boolean {
  return num % 2 === 0;
}

Außerdem ist es so auch lesbarer 😉

Dann können wir mit der Hauptfunktion anfangen!

Die erste Zeile meiner Hauptfunktion:
export function evenDigitSquares(a: number, b: number): number[] {
Wir erstellen uns unsere Variablen für das Ergebnis, den Anfang und das Ende des äußeren Loops:
const sequence: number[] = [];
const start = Math.sqrt(a);
const end = Math.sqrt(b);
Dann der Loop:
  loopRoots: for (let i = start; i <= end; i++) {

Damit wir aus dem zweiten Loop zum nächsten Element des ersten Loops springen können, verpassen wir unserem for-Loop hier ein Label (loopRoots).

Dann der Test, ob die aktuelle Zahl gerade ist:
if (!isEven(i)) continue;

Wenn nicht, können wir direkt mit dem nächsten Element weitermachen. Dafür verwende ich hier das continue-Keyword.

Ansonsten besorgen wir uns die Ziffern des Quadrats:
const square = i ** 2;
const digits = square.toString().split("").map(Number);

Mit .map(Number) wandeln wir alle Ziffern gleich in Zahlen um.

Dann der (innere) Loop durch die Ziffern:
    for (const digit of digits) {
Hier testen wir jede Ziffer auf Geradeheit*:
      if (!isEven(digit)) continue loopRoots;
    }
* HINWEIS
Das Wort hab ich mir gerade ganz alleine ausgedacht, cool oder?!

Wenn die Ziffer nicht gerade ist, kann sie keine P.E.D.P.S. sein und wir können direkt zur nächsten Zahl (im äußeren Loop) springen.

Hier kommt unser Label zum Einsatz! Da wir mit continue nur zum nächsten Element des inneren Loops springen können, setzen wir einfach den Labelnamen des äußeren Loops dahinter.

Sollte es ein Quadrat durch den Ziffern-Loop geschafft haben, hängen wir es an unser Ergebnis-Array:
    sequence.push(square);
  }
Nach dem äußeren Loop dann nur noch das Ergebnis zurückgeben:
  return sequence;
}
Voilá! 💪

Fragen?

Komplettlösung
export function evenDigitSquares(a: number, b: number): number[] {
  const sequence: number[] = [];
  const start = Math.sqrt(a);
  const end = Math.sqrt(b);

  loopRoots: for (let i = start; i <= end; i++) {
    if (!isEven(i)) continue;
    const square = i ** 2;
    const digits = square.toString().split("").map(Number);

    for (const digit of digits) {
      if (!isEven(digit)) continue loopRoots;
    }

    sequence.push(square);
  }

  return sequence;
}

function isEven(num: number): boolean {
  return num % 2 === 0;
}

Feedback

Schreib mir!