367 Stimmen

Wie kann man ein zweidimensionales Feld drehen?

Inspiriert durch Beitrag von Raymond Chen Wenn Sie ein zweidimensionales 4x4-Array haben, schreiben Sie eine Funktion, die es um 90 Grad dreht. Raymond verlinkt auf eine Lösung in Pseudocode, aber ich würde gerne etwas aus der Praxis sehen.

[1][2][3][4]
[5][6][7][8]
[9][0][1][2]
[3][4][5][6]

Wird:

[3][9][5][1]
[4][0][6][2]
[5][1][7][3]
[6][2][8][4]

Update : Die Antwort von Nick ist die einfachste, aber gibt es eine Möglichkeit, es besser zu machen als n^2? Was wäre, wenn die Matrix 10000x10000 wäre?

487voto

dimple Punkte 631

O(n^2) Zeit und O(1) Raum Algorithmus ( ohne irgendwelche Umgehungslösungen und Mauscheleien! )

Drehen um +90:

  1. Transponieren
  2. Jede Zeile umkehren

Drehen Sie um -90:

Methode 1 :

  1. Transponieren
  2. Jede Spalte umkehren

Methode 2 :

  1. Jede Zeile umkehren
  2. Transponieren

Drehen um +180:

Methode 1 : Zweimal um +90 drehen

Methode 2 : Jede Zeile umkehren und dann jede Spalte umkehren (Transponieren)

Drehen um -180:

Methode 1 : Zweimaliges Drehen um -90

Methode 2 : Jede Spalte umkehren und dann jede Zeile umkehren

Methode 3 : Drehen um +180, da sie gleich sind

262voto

Jack Punkte 9483

Ich möchte noch ein wenig mehr Details hinzufügen. In dieser Antwort werden Schlüsselbegriffe wiederholt, das Tempo ist langsam und absichtlich repetitiv. Die hier angebotene Lösung ist nicht die syntaktisch kompakteste, sie ist jedoch für diejenigen gedacht, die lernen wollen, was eine Matrixrotation ist und wie sie umgesetzt wird.

Erstens: Was ist eine Matrix? Für die Zwecke dieser Antwort ist eine Matrix einfach ein Gitter, bei dem die Breite und die Höhe gleich sind. Beachten Sie, dass die Breite und Höhe einer Matrix unterschiedlich sein können, aber der Einfachheit halber werden in diesem Lernprogramm nur Matrizen mit gleicher Breite und Höhe betrachtet ( quadratische Matrizen ). Und ja, Matrizen ist der Plural von Matrix.

Beispielmatrizen sind: 2×2, 3×3 oder 5×5. Oder, allgemeiner ausgedrückt, N×N. Eine 2×2-Matrix hat 4 Quadrate, weil 2×2=4 ist. Eine 5×5-Matrix hat 25 Quadrate, weil 5×5=25. Jedes Quadrat wird als Element oder Eintrag bezeichnet. Wir stellen jedes Element mit einem Punkt dar ( . ) in den unten stehenden Diagrammen:

2×2-Matrix

. .
. .

3×3-Matrix

. . .
. . .
. . .

4×4-Matrix

. . . .
. . . .
. . . .
. . . .

Was bedeutet es also, eine Matrix zu drehen? Nehmen wir eine 2×2-Matrix und setzen wir einige Zahlen in jedes Element, damit die Drehung beobachtet werden kann:

0 1
2 3

Dreht man dies um 90 Grad, erhält man:

2 0
3 1

Wir haben die gesamte Matrix buchstäblich einmal nach rechts gedreht, so wie man das Lenkrad eines Autos dreht. Es kann hilfreich sein, sich vorzustellen, dass man die Matrix auf die rechte Seite "kippt". Wir wollen eine Funktion in Python schreiben, die eine Matrix nimmt und sie einmal nach rechts dreht. Die Funktionssignatur wird sein:

def rotate(matrix):
    # Algorithm goes here.

Die Matrix wird über ein zweidimensionales Array definiert:

matrix = [
    [0,1],
    [2,3]
]

Daher greift die erste Indexposition auf die Zeile zu. Die zweite Indexposition greift auf die Spalte zu:

matrix[row][column]

Wir definieren eine Hilfsfunktion zum Drucken einer Matrix.

def print_matrix(matrix):
    for row in matrix:
        print row

Eine Methode zum Drehen einer Matrix besteht darin, eine Ebene nach der anderen zu bearbeiten. Aber was ist eine Ebene? Denken Sie an eine Zwiebel. Genau wie bei den Schichten einer Zwiebel bewegen wir uns mit jeder entfernten Schicht auf das Zentrum zu. Eine andere Analogie ist eine Matrjoschka-Puppe oder ein Spiel, bei dem das Paket weitergegeben wird.

Die Breite und Höhe einer Matrix bestimmen die Anzahl der Schichten in dieser Matrix. Verwenden wir für jede Ebene unterschiedliche Symbole:

Eine 2×2-Matrix hat 1 Schicht

. .
. .

Eine 3×3-Matrix hat 2 Schichten

. . .
. x .
. . .

Eine 4×4-Matrix hat 2 Schichten

. . . .
. x x .
. x x .
. . . .

Eine 5×5-Matrix hat 3 Schichten

. . . . .
. x x x .
. x O x .
. x x x .
. . . . .

Eine 6×6-Matrix hat 3 Schichten

. . . . . .
. x x x x .
. x O O x .
. x O O x .
. x x x x .
. . . . . .

Eine 7×7-Matrix hat 4 Schichten

. . . . . . .
. x x x x x .
. x O O O x .
. x O - O x .
. x O O O x .
. x x x x x .
. . . . . . .

Sie werden feststellen, dass das Erhöhen der Breite und Höhe einer Matrix um eins nicht immer die Anzahl der Ebenen erhöht. Nimmt man die obigen Matrizen und tabelliert die Ebenen und Dimensionen, so stellt man fest, dass sich die Anzahl der Ebenen bei jeder zweimaligen Erhöhung von Breite und Höhe einmal erhöht:

+-----+--------+
| N×N | Layers |
+-----+--------+
| 1×1 |      1 |
| 2×2 |      1 |
| 3×3 |      2 |
| 4×4 |      2 |
| 5×5 |      3 |
| 6×6 |      3 |
| 7×7 |      4 |
+-----+--------+

Es müssen jedoch nicht alle Ebenen gedreht werden. Eine 1×1-Matrix ist vor und nach der Drehung die gleiche. Die zentrale 1×1-Schicht ist vor und nach der Drehung immer gleich groß, egal wie groß die Gesamtmatrix ist:

+-----+--------+------------------+
| N×N | Layers | Rotatable Layers |
+-----+--------+------------------+
| 1×1 |      1 |                0 |
| 2×2 |      1 |                1 |
| 3×3 |      2 |                1 |
| 4×4 |      2 |                2 |
| 5×5 |      3 |                2 |
| 6×6 |      3 |                3 |
| 7×7 |      4 |                3 |
+-----+--------+------------------+

Wie kann man bei einer N×N-Matrix programmatisch die Anzahl der zu drehenden Ebenen bestimmen? Wenn wir die Breite oder Höhe durch zwei teilen und den Rest ignorieren, erhalten wir die folgenden Ergebnisse.

+-----+--------+------------------+---------+
| N×N | Layers | Rotatable Layers |   N/2   |
+-----+--------+------------------+---------+
| 1×1 |      1 |                0 | 1/2 = 0 |
| 2×2 |      1 |                1 | 2/2 = 1 |
| 3×3 |      2 |                1 | 3/2 = 1 |
| 4×4 |      2 |                2 | 4/2 = 2 |
| 5×5 |      3 |                2 | 5/2 = 2 |
| 6×6 |      3 |                3 | 6/2 = 3 |
| 7×7 |      4 |                3 | 7/2 = 3 |
+-----+--------+------------------+---------+

Beachten Sie, wie N/2 mit der Anzahl der Ebenen übereinstimmt, die gedreht werden müssen? Manchmal ist die Anzahl der drehbaren Ebenen eine weniger als die Gesamtzahl der Ebenen in der Matrix. Dies ist der Fall, wenn die innerste Schicht nur aus einem Element besteht (d. h. eine 1×1-Matrix) und daher nicht gedreht werden muss. Sie wird einfach ignoriert.

Wir werden diese Information zweifellos in unserer Funktion zum Drehen einer Matrix benötigen, also fügen wir sie jetzt hinzu:

def rotate(matrix):
    size = len(matrix)
    # Rotatable layers only.
    layer_count = size / 2

Jetzt wissen wir, was Ebenen sind und wie wir die Anzahl der Ebenen bestimmen, die tatsächlich gedreht werden müssen. Wie isolieren wir eine einzelne Ebene, damit wir sie drehen können? Zunächst untersuchen wir eine Matrix von der äußersten Schicht nach innen bis zur innersten Schicht. Eine 5×5-Matrix hat insgesamt drei Schichten und zwei Schichten, die gedreht werden müssen:

. . . . .
. x x x .
. x O x .
. x x x .
. . . . .

Betrachten wir zunächst die Spalten. Die Position der Spalten, die die äußerste Schicht definieren, sind, wenn wir von 0 aus zählen, 0 und 4:

+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
|        | . . . . . |
|        | . x x x . |
|        | . x O x . |
|        | . x x x . |
|        | . . . . . |
+--------+-----------+

0 und 4 sind auch die Positionen der Zeilen für die äußerste Schicht.

+-----+-----------+
| Row |           |
+-----+-----------+
|   0 | . . . . . |
|   1 | . x x x . |
|   2 | . x O x . |
|   3 | . x x x . |
|   4 | . . . . . |
+-----+-----------+

Dies wird immer der Fall sein, da die Breite und die Höhe gleich sind. Daher können wir die Spalten- und Zeilenpositionen einer Ebene mit nur zwei Werten (statt vier) definieren.

Auf der zweiten Ebene befinden sich die Spalten 1 und 3. Und, ja, Sie haben es erraten, das Gleiche gilt für die Zeilen. Es ist wichtig zu verstehen, dass wir die Zeilen- und Spaltenpositionen sowohl inkrementieren als auch dekrementieren müssen, wenn wir uns in die nächste Ebene bewegen.

+-----------+---------+---------+---------+
|   Layer   |  Rows   | Columns | Rotate? |
+-----------+---------+---------+---------+
| Outermost | 0 and 4 | 0 and 4 | Yes     |
| Inner     | 1 and 3 | 1 and 3 | Yes     |
| Innermost | 2       | 2       | No      |
+-----------+---------+---------+---------+

Um also jede Schicht zu untersuchen, brauchen wir eine Schleife mit aufsteigenden und absteigenden Zählern, die sich von der äußersten Schicht aus nach innen bewegen. Wir nennen dies unsere "Schichtschleife".

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    for layer in range(0, layer_count):
        first = layer
        last = size - first - 1
        print 'Layer %d: first: %d, last: %d' % (layer, first, last)

# 5x5 matrix
matrix = [
    [ 0, 1, 2, 3, 4],
    [ 5, 6, 6, 8, 9],
    [10,11,12,13,14],
    [15,16,17,18,19],
    [20,21,22,23,24]
]

rotate(matrix)

Der obige Code durchläuft in einer Schleife die (Zeilen- und Spalten-) Positionen aller Ebenen, die gedreht werden müssen.

Layer 0: first: 0, last: 4
Layer 1: first: 1, last: 3

Wir haben jetzt eine Schleife, die die Positionen der Zeilen und Spalten jeder Ebene liefert. Die Variablen first y last die Indexposition der ersten und letzten Zeile und Spalte bestimmen. Beziehen Sie sich auf unsere Zeilen- und Spaltentabellen:

+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
|        | . . . . . |
|        | . x x x . |
|        | . x O x . |
|        | . x x x . |
|        | . . . . . |
+--------+-----------+

+-----+-----------+
| Row |           |
+-----+-----------+
|   0 | . . . . . |
|   1 | . x x x . |
|   2 | . x O x . |
|   3 | . x x x . |
|   4 | . . . . . |
+-----+-----------+

So können wir durch die Schichten einer Matrix navigieren. Jetzt brauchen wir eine Möglichkeit, innerhalb einer Ebene zu navigieren, damit wir Elemente in dieser Ebene verschieben können. Beachten Sie, dass Elemente niemals von einer Ebene zur anderen "springen", sondern sich innerhalb ihrer jeweiligen Ebene bewegen.

Durch Drehen der einzelnen Elemente in einer Ebene wird die gesamte Ebene gedreht. Wenn Sie alle Ebenen einer Matrix drehen, wird die gesamte Matrix gedreht. Dieser Satz ist sehr wichtig, also versuchen Sie bitte, ihn zu verstehen, bevor Sie fortfahren.

Jetzt brauchen wir eine Möglichkeit, die Elemente tatsächlich zu verschieben, d. h. jedes Element zu drehen, und anschließend die Ebene und schließlich die Matrix. Der Einfachheit halber werden wir auf eine 3x3-Matrix zurückgreifen - mit einer drehbaren Ebene.

0 1 2
3 4 5
6 7 8

Unsere Ebenenschleife liefert die Indizes der ersten und letzten Spalte sowie der ersten und letzten Zeile:

+-----+-------+
| Col | 0 1 2 |
+-----+-------+
|     | 0 1 2 |
|     | 3 4 5 |
|     | 6 7 8 |
+-----+-------+

+-----+-------+
| Row |       |
+-----+-------+
|   0 | 0 1 2 |
|   1 | 3 4 5 |
|   2 | 6 7 8 |
+-----+-------+

Da unsere Matrizen immer quadratisch sind, benötigen wir nur zwei Variablen, first y last , da die Indexpositionen für Zeilen und Spalten gleich sind.

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    # Our layer loop i=0, i=1, i=2
    for layer in range(0, layer_count):

        first = layer
        last = size - first - 1

        # We want to move within a layer here.

Die Variablen "first" und "last" können leicht verwendet werden, um auf die vier Ecken einer Matrix zu verweisen. Dies liegt daran, dass die Ecken selbst durch verschiedene Permutationen von first y last (ohne Subtraktion, Addition oder Offset dieser Variablen):

+---------------+-------------------+-------------+
| Corner        | Position          | 3x3 Values  |
+---------------+-------------------+-------------+
| top left      | (first, first)    | (0,0)       |
| top right     | (first, last)     | (0,2)       |
| bottom right  | (last, last)      | (2,2)       |
| bottom left   | (last, first)     | (2,0)       |
+---------------+-------------------+-------------+

Aus diesem Grund beginnen wir mit der Rotation an den äußeren vier Ecken - wir werden diese zuerst drehen. Markieren wir sie mit * .

* 1 *
3 4 5
* 7 *

Wir wollen die einzelnen * mit dem * rechts daneben. Lassen Sie uns also unsere Ecken ausdrucken, die nur mit verschiedenen Permutationen von first y last :

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2
    for layer in range(0, layer_count):

        first = layer
        last = size - first - 1

        top_left = (first, first)
        top_right = (first, last)
        bottom_right = (last, last)
        bottom_left = (last, first)

        print 'top_left: %s' % (top_left)
        print 'top_right: %s' % (top_right)
        print 'bottom_right: %s' % (bottom_right)
        print 'bottom_left: %s' % (bottom_left)

matrix = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]

rotate(matrix)

Die Ausgabe sollte sein:

top_left: (0, 0)
top_right: (0, 2)
bottom_right: (2, 2)
bottom_left: (2, 0)

Jetzt können wir ganz einfach jede der Ecken innerhalb unserer Ebenenschleife austauschen:

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2
    for layer in range(0, layer_count):

        first = layer
        last = size - first - 1

        top_left = matrix[first][first]
        top_right = matrix[first][last]
        bottom_right = matrix[last][last]
        bottom_left = matrix[last][first]

        # bottom_left -> top_left
        matrix[first][first] = bottom_left
        # top_left -> top_right
        matrix[first][last] = top_left
        # top_right -> bottom_right
        matrix[last][last] = top_right
        # bottom_right -> bottom_left
        matrix[last][first] = bottom_right

print_matrix(matrix)
print '---------'
rotate(matrix)
print_matrix(matrix)

Matrix vor dem Drehen der Ecken:

[0, 1, 2]
[3, 4, 5]
[6, 7, 8]

Matrix nach dem Drehen der Ecken:

[6, 1, 0]
[3, 4, 5]
[8, 7, 2]

Großartig! Wir haben erfolgreich jede Ecke der Matrix gedreht. Aber wir haben die Elemente in der Mitte jeder Ebene nicht gedreht. Es ist klar, dass wir eine Möglichkeit brauchen, innerhalb einer Ebene zu iterieren.

Das Problem ist, dass die einzige Schleife in unserer Funktion bisher (unsere Ebenenschleife) bei jeder Iteration zur nächsten Ebene wechselt. Da unsere Matrix nur eine drehbare Ebene hat, wird die Ebenenschleife nach dem Drehen nur der Ecken beendet. Schauen wir uns an, was mit einer größeren 5×5-Matrix passiert (bei der zwei Ebenen gedreht werden müssen). Der Funktionscode wurde weggelassen, aber er bleibt derselbe wie oben:

matrix = [
[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]
]
print_matrix(matrix)
print '--------------------'
rotate(matrix)
print_matrix(matrix)

Die Ausgabe ist:

[20,  1,  2,  3,  0]
[ 5, 16,  7,  6,  9]
[10, 11, 12, 13, 14]
[15, 18, 17,  8, 19]
[24, 21, 22, 23,  4]

Es sollte nicht überraschen, dass die Ecken der äußersten Schicht gedreht wurden, aber Sie können auch feststellen, dass die Ecken der nächsten Schicht (nach innen) ebenfalls gedreht wurden. Das macht Sinn. Wir haben Code geschrieben, um durch die Ebenen zu navigieren und auch die Ecken der einzelnen Ebenen zu drehen. Das fühlt sich wie ein Fortschritt an, aber leider müssen wir einen Schritt zurück machen. Es ist einfach nicht sinnvoll, zur nächsten Ebene überzugehen, bevor die vorherige (äußere) Ebene nicht vollständig gedreht wurde. Das heißt, bis jedes Element in der Ebene gedreht worden ist. Nur die Ecken zu drehen, reicht nicht aus!

Atmen Sie tief durch. Wir brauchen eine weitere Schleife. Und zwar eine verschachtelte Schleife. Die neue, verschachtelte Schleife verwendet die first y last Variablen sowie einen Offset, um innerhalb einer Ebene zu navigieren. Wir nennen diese neue Schleife unsere "Elementschleife". Die Elementschleife besucht jedes Element in der oberen Zeile, jedes Element auf der rechten Seite, jedes Element in der unteren Zeile und jedes Element auf der linken Seite.

  • Um sich in der obersten Zeile vorwärts zu bewegen, muss die Spalte Index inkrementiert werden.
  • Um auf der rechten Seite nach unten zu gelangen, muss der Zeilenindex inkrementiert werden.
  • Die Rückwärtsbewegung entlang des Bodens erfordert die Spalte Index dekrementiert werden.
  • Um auf der linken Seite nach oben zu gelangen, muss der Zeilenindex dekrementiert werden.

Das hört sich kompliziert an, ist aber ganz einfach, weil die Anzahl der Inkremente und Dekremente auf allen vier Seiten der Matrix gleich bleibt. Zum Beispiel:

  • Verschieben Sie 1 Element in der obersten Reihe.
  • Bewege 1 Element auf der rechten Seite nach unten.
  • Verschiebe 1 Element in der unteren Reihe nach hinten.
  • Bewege 1 Element auf der linken Seite nach oben.

Das bedeutet, dass wir eine einzelne Variable in Kombination mit dem first y last Variablen innerhalb einer Ebene zu verschieben. Es ist hilfreich zu wissen, dass die Bewegung über die oberste Reihe und die Bewegung nach unten auf der rechten Seite jeweils eine Inkrementierung erfordert. Wenn Sie sich rückwärts entlang der unteren Reihe und auf der linken Seite nach oben bewegen, müssen Sie beide dekrementieren.

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    # Move through layers (i.e. layer loop).
    for layer in range(0, layer_count):

            first = layer
            last = size - first - 1

            # Move within a single layer (i.e. element loop).
            for element in range(first, last):

                offset = element - first

                # 'element' increments column (across right)
                top = (first, element)
                # 'element' increments row (move down)
                right_side = (element, last)
                # 'last-offset' decrements column (across left)
                bottom = (last, last-offset)
                # 'last-offset' decrements row (move up)
                left_side = (last-offset, first)

                print 'top: %s' % (top)
                print 'right_side: %s' % (right_side)
                print 'bottom: %s' % (bottom)
                print 'left_side: %s' % (left_side)

Jetzt müssen wir nur noch die Oberseite der rechten Seite, die rechte Seite der Unterseite, die Unterseite der linken Seite und die linke Seite der Oberseite zuordnen. Wenn wir das alles zusammenfügen, erhalten wir:

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    for layer in range(0, layer_count):
        first = layer
        last = size - first - 1

        for element in range(first, last):
            offset = element - first

            top = matrix[first][element]
            right_side = matrix[element][last]
            bottom = matrix[last][last-offset]
            left_side = matrix[last-offset][first]

            matrix[first][element] = left_side
            matrix[element][last] = top
            matrix[last][last-offset] = right_side
            matrix[last-offset][first] = bottom

Gegeben die Matrix:

0,  1,  2  
3,  4,  5  
6,  7,  8 

Unser rotate Funktion führt zu:

6,  3,  0  
7,  4,  1  
8,  5,  2

166voto

Nick Berardi Punkte 53415

Hier ist es in C#

int[,] array = new int[4,4] {
    { 1,2,3,4 },
    { 5,6,7,8 },
    { 9,0,1,2 },
    { 3,4,5,6 }
};

int[,] rotated = RotateMatrix(array, 4);

static int[,] RotateMatrix(int[,] matrix, int n) {
    int[,] ret = new int[n, n];

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            ret[i, j] = matrix[n - j - 1, i];
        }
    }

    return ret;
}

136voto

recursive Punkte 80517

Python:

rotated = list(zip(*original[::-1]))

und gegen den Uhrzeigersinn:

rotated_ccw = list(zip(*original))[::-1]

Wie das funktioniert:

zip(*original) tauscht die Achsen von 2d-Arrays aus, indem es die entsprechenden Elemente aus Listen in neue Listen stapelt. (Die * Betreiber weist die Funktion an, die enthaltenen Listen in Argumente aufzuteilen)

>>> list(zip(*[[1,2,3],[4,5,6],[7,8,9]]))
[[1,4,7],[2,5,8],[3,6,9]]

Le [::-1] Anweisung kehrt Array-Elemente um (siehe Erweiterte Schnitte ou diese Frage ):

>>> [[1,2,3],[4,5,6],[7,8,9]][::-1]
[[7,8,9],[4,5,6],[1,2,3]]

Die Kombination der beiden ergibt schließlich die Rotationstransformation.

Die Änderung der Platzierung von [::-1] kehrt die Listen in den verschiedenen Ebenen der Matrix um.

81voto

dagorym Punkte 5395

Hier ist eine, die die Drehung an Ort und Stelle, anstatt mit einem völlig neuen Array, um das Ergebnis zu halten tut. Ich habe die Initialisierung des Arrays und das Ausdrucken weggelassen. Dies funktioniert nur für quadratische Arrays, aber sie können beliebig groß sein. Der Speicheraufwand entspricht der Größe eines Elements des Arrays, so dass Sie die Rotation eines beliebig großen Arrays durchführen können.

int a[4][4];
int n = 4;
int tmp;
for (int i = 0; i < n / 2; i++)
{
    for (int j = i; j < n - i - 1; j++)
    {
        tmp             = a[i][j];
        a[i][j]         = a[j][n-i-1];
        a[j][n-i-1]     = a[n-i-1][n-j-1];
        a[n-i-1][n-j-1] = a[n-j-1][i];
        a[n-j-1][i]     = tmp;
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X