Fragen zum Zähneputzen mit verknüpfter Liste (4–8)

Inhaltsverzeichnis

umgekehrt verknüpfte Liste

 Rückkehr zum mittleren Knoten

 Zählen Sie bis zu k Knoten herunter

 Partition mit verknüpfter Liste

 Urteilspalindrom


umgekehrt verknüpfte Liste

Bei Fragen zu einfach verknüpften Listen sind wir auf eine umgekehrt verknüpfte Liste gestoßen. Damals verwendeten wir die Methode des Einfügens des Kopfes, um den umgekehrten Effekt zu erzielen. Kann der Zeiger umgekehrt werden? Die Antwort ist ja.

  

Der Zweck der Verwendung von drei Zeigern besteht darin, die Daten der folgenden Knoten aufzuzeichnen, andernfalls fehlen die folgenden Adressen . Schließlich kann sich die logische Struktur von der physischen Struktur unterscheiden. Es ist ersichtlich, dass die Endbedingung darin besteht, dass n2 stoppt, wenn es leer wird.

Basierend auf der vorherigen umgekehrt verknüpften Liste haben wir jetzt neben dem Einstecken des Kopfes eine neue Methode:

Lauch

struct ListNode* reverseList(struct ListNode* head)
{
    if(head == NULL)//防止空指针解引用
    {
        return NULL;
    }
    struct ListNode* n1,*n2,*n3;
    n1 = NULL;
    n2 = head;
    n3 = n2->next;
    while(n2)//结束条件
    {
        n2->next = n1;
        n1 = n2;
        n2 = n3;
        if(n3)//n3为空时保持原样
        {
            n3 = n3->next;
        }
    }
    return n1;
}

 Rückkehr zum mittleren Knoten

Lauch

Eine Idee zum Auffinden der Zwischenknoten der verknüpften Liste ist der Geschwindigkeitszeiger : Jedes Mal, wenn der langsame Zeiger einen Schritt macht, macht der schnelle Zeiger zwei Schritte . Auf diese Weise wird der Zwischenknoten gefunden , nachdem die verknüpfte Liste nur einmal durchlaufen wurde .

struct ListNode* middleNode(struct ListNode* head)
{
    struct ListNode* fast=head,*slow = head;
    while(fast && fast->next)
    {
        fast = fast ->next->next;
        //fast更新后判断,返回第一个中间结点:if(fast!=NULL)
        slow = slow->next;
    }
    return slow;//快慢指针

}

 Zählen Sie bis zu k Knoten herunter

Die letzten k Knoten in der verknüpften Liste

Diese Frage ähnelt der vorherigen, der Unterschied besteht darin, dass wir nicht wissen, wie lang k ist. Dazu können wir die schnellen und langsamen Zeiger festlegen , schnell zuerst k Schritte oder k-1 Schritte ausführen lassen und dann die zwei Zeiger bewegen sich zusammen .

Es ist zu beachten, dass eine leere verknüpfte Liste zurückgegeben wird, wenn weniger als k Schritte vorhanden sind .

truct ListNode* FindKthToTail(struct ListNode* pHead, int k ) {
    struct ListNode* slow,*fast;
    slow = fast = pHead;
    while(k--)//k步
    {
        if(fast == NULL)//不足k步
        {
                return NULL;
        }
        fast = fast->next;
    }
    while(fast)//走k步结束条件
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

 Partition mit verknüpfter Liste

 Diese Frage gilt als relativ schwierig und erfordert, dass die relative Reihenfolge nach der Teilung nicht geändert werden kann. Hier erstellen wir zwei verknüpfte Listen .

Ein Datensatz mit Daten kleiner als x und ein Datensatz mit Daten gleich und größer als x werden nacheinander am Ende eingefügt . Verbinden Sie abschließend die beiden verknüpften Listen. Wir alle erstellen einen Sentinel-Knoten für die neue verknüpfte Liste (um das anfängliche leere Urteil und den Fall zu vermeiden, dass eine der verknüpften Listen leer ist.)

  

Ich habe dieses Bild durcheinander gezeichnet, aber die Idee ist sehr klar. Erstellen Sie einen Sentinel-Knoten, vergleichen, einfügen, leeren, verbinden, freigeben , alles in einem Arbeitsgang.

Die Implementierung in C wird hier nicht unterstützt, daher implementieren wir sie zuerst in C++. Der Unterschied besteht darin, dass die Strukturdefinition keine Struktur schreiben muss.

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        ListNode *greaterhead,*greatertail;
        greaterhead=greatertail=(ListNode *)malloc(sizeof(ListNode));
        ListNode *smallerhead, *smallertail;
        smallertail=smallerhead=(ListNode *)malloc(sizeof(ListNode));
    while(pHead==NULL)
    {
        return NULL;
    }
     ListNode* cur = pHead;
    while(cur)
   { if(cur->val<x)
    {
        smallertail->next = cur;
        smallertail =  smallertail->next;
    }
    if(cur->val>=x)
     {
        greatertail->next = cur;
        greatertail = greatertail->next;
    }
     cur = cur->next;
   }
   smallertail->next = greaterhead->next;//连结
   greatertail->next = NULL;//置空
    ListNode*Next = smallerhead->next;//返回
   free(smallerhead);
   free(greaterhead);
   return Next;
    }

};

Hier liegt ein kleines Missverständnis im Unterschied zwischen der physischen Struktur und der logischen Struktur vor. Aus der Abbildung geht hervor, dass hinter den am Ende eingefügten Daten kein anderer Inhalt steckt. Tatsächlich zeigt der nächste Zeiger immer noch auf den nächsten Knoten der ursprünglichen verknüpften Liste, obwohl es sich um zwei neue verknüpfte Listen handelt. Eine neue verknüpfte Liste wird erstellt, aber tatsächlich wird nur der Sentinel neu geöffnet, und er wird nur auf der ursprünglichen verknüpften Liste ausgeführt , daher sollte der letzte Knoten des größeren Zeigers ausgeblendet sein

Urteilspalindrom

 Die normale Idee besteht darin, eine verknüpfte Liste zu kopieren und sie dann auf dieser Basis umzukehren. Aber eine solche Raumkomplexität wird zu O(N) . Hier ist eine neuartige Methode: Kehren Sie entsprechend der Symmetrie des Palindroms die mittleren und nachfolgenden Knoten der verknüpften Liste um.

  

In den beiden oben genannten Fällen besteht die Endbedingung für den Vergleich darin, dass eine Seite leer ist, um den Vergleich zu stoppen.

Zufälligerweise haben wir das Finden von Zwischenknoten und das Umkehren der verknüpften Liste implementiert, sodass wir hier direkt eine Kopie des Codes kopieren können.

struct ListNode* reverseList(struct ListNode* head) {
    if (head == NULL) { //防止空指针解引用
        return NULL;
    }
    struct ListNode* n1, *n2, *n3;
    n1 = NULL;
    n2 = head;
    n3 = n2->next;
    while (n2) { //结束条件
        n2->next = n1;
        n1 = n2;
        n2 = n3;
        if (n3) { //n3为空时保持原样
            n3 = n3->next;
        }
    }
    return n1;
}
struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode* fast = head, *slow = head;
    while (fast && fast->next) {
        fast = fast ->next->next;
        //fast更新后判断,返回第一个中间结点:if(fast!=NULL)
        slow = slow->next;
    }
    return slow;//快慢指针

}
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        struct ListNode* mid = middleNode(A);
    struct ListNode* rhead = reverseList(mid);
    while(A && rhead)//一方为空停止
    {
       if( A->val != rhead->val)
       {
        return false;
       }
       A = A->next;
       rhead = rhead->next;
    }
    return true;
    }
};

Je suppose que tu aimes

Origine blog.csdn.net/dwededewde/article/details/131252383
conseillé
Classement