Codewars Lösung | Typing series #1 --> the [backspace] function


coden
Codewars. Achieve mastery through challenge.
Daniel Kaser|16. Oktober 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:Typing series #1 --> the [backspace] function
Level:6 kyu
Sprache:TypeScript

Beschreibung:

This kata is a harder version of this kata: https://www.codewars.com/kata/5727bb0fe81185ae62000ae3

If you haven't done it yet, you should do that one first before doing this one.

You are given a string of letters that you need to type out. In the string there is a special function: [backspace]. Once you encounter a [backspace] , you delete the character right before it. If there is nothing to backspace , just carry on. Return the final string .

e.g. oopp[backspace]s return oops (delete the p)

Walkthrough:

o
oo
oop
oopp
oop [backspace]
oops

e.g. ooppp[backspace][backspace]s return oops (delete both p's)

Walkthrough:

o
oo
oop
oopp
ooppp
oopp [backspace]
oop [backspace]
oops

e.g. a[backspace][backspace]ooppp[backspace][backspace]s return oops

Walkthrough:

a
[nothing]
[nothing]
o
oo
oop
oopp
ooppp
oopp [backspace]
oop [backspace]
oops

But there's a twist! [backspace][backspace][backspace] can appear as [backspace]*3 or even [backspace]*2[backspace]

Basically, [backspace][backspace] ... [backspace] n times can appear as [backspace]*n (n can even be 1, but not less than 1 ([backspace]*0 will not occur))

e.g. a[backspace]*2oopppp[backspace]*2[backspace]s return oops

Walkthrough:

a
[nothing] [backspace]*2
o
oo
oop
oopp
ooppp
oopppp
oopp [backspace]*2
oop [backspace]
oops

To make it easier, only letters, spaces. and the [backspace] function will be in the initial string.

Good luck!


Check out the rest of the kata in this series!

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

Als Erstes empfehle ich dringend dem Rat des Kata-Autors zu folgen und den Vorgänger anzuschauen.

Schritt 2

Wir werden eine Variable brauchen um unser Ergebnis zu speichern, am besten ein Array.

Schritt 3

Dann können wir als Nächstes die multiplen Backspaces in einzelne auflösen. Dafür können wir uns eine kleine Helferfunktion basteln.

Schritt 4

Die einzelnen Backspaces können wir dann jeweils z.B. durch ein # ersetzen.

Schritt 5

Jetzt können wir durch den String loopen.

Schritt 6

Wenn das aktuelle Zeichen ein # ist, entfernen wir das letzte Element in unserem Ergebnis-Array.

Schritt 7

Ansonsten hängen wir das aktuelle Zeichen an unser Ergebnis an.

Schritt 8

Nach dem Loop nur noch das Ergebnis als String zurückgeben.

Code

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

Lösungsschritte
Als Erstes die Helferfunktion um die multiplen Backspaces in einzelne aufzulösen. Meine erste Zeile:
function resolveMultipleBackspaces(str: string): string {
Dann die Logik für das Ersetzen:
  return str.replace(/\[backspace]\*\d+/g, (match) => {

Die RegEx /\[backspace]\*\d+/g matcht alle Zeichenfolgen mit [backspace] und * gefolgt von einer (oder mehr) Ziffer(n). Die erste eckige Klammer, das * und das d müssen wir jeweils mit einem \ escapen.

Für jeden Treffer wird eine Funktion ausgeführt, der wir das aktuelle match übergeben.

Das return können wir hier bereits davor schreiben.

Jetzt die Logik für das Innere der Replace-Funktion:
const num = Number(match.split("*")[1]);

Wir speichern uns die Zahl am Ende jedes Treffers in eine Variable.

Dann können wir so viele [backspace] zurückgeben, wie die Zahl hergibt:
    return "[backspace]".repeat(num);
  });
}

Und das war’s schon fürs Helferlein. Weiter geht’s mit der Hauptfunktion.

Die erste Zeile meiner Hauptfunktion (ich habe s in str umbenannt):
export function solve(str: string): string {
Dann unsere Variable für das Ergebnis:
const result: string[] = [];
Mit unserer Hilfsfunktion können wir jetzt die multiplen Backspaces (z.B. [backspace]*2) in einzelne [backspace] auflösen:
const resolvedBackspaces = resolveMultipleBackspaces(str);

[backspace]*2 wird also zu [backspace][backspace] usw.

Dann können wir alle [backspace] durch ein # ersetzen:
const backspacesReplaced = resolvedBackspaces.replace(/\[backspace]/g, "#");
Jetzt der Loop:
  for (const char of backspacesReplaced) {

Da wir durch den String loopen können, empfiehlt sich hier ein einfacher for...of-Loop.

Wenn das aktuelle Zeichen ein # ist, entfernen wir das letzte Element aus unserem Ergebnis-Array:
if (char === "#") result.pop();
Ansonsten hängen wir das aktuelle Zeichen ans Ergebnis-Array an:
    else result.push(char);
  }
Zum Schluss nur noch das Ergebnis als String zurückgeben:
  return result.join("");
}
Voilá! 💪

Zugegeben, man hätte es etwas performanter gestalten können. Dann hätte allerdings die Lesbarkeit etwas gelitten. Ich habe mich hier für die Lesbarkeit entschieden!

Fragen?

Komplettlösung
export function solve(str: string): string {
  const result: string[] = [];

  const resolvedBackspaces = resolveMultipleBackspaces(str);
  const backspacesReplaced = resolvedBackspaces.replace(/\[backspace]/g, "#");

  for (const char of backspacesReplaced) {
    if (char === "#") result.pop();
    else result.push(char);
  }

  return result.join("");
}

function resolveMultipleBackspaces(str: string): string {
  return str.replace(/\[backspace]\*\d+/g, (match) => {
    const num = Number(match.split("*")[1]);
    return "[backspace]".repeat(num);
  });
}

Feedback

Schreib mir!