C++判斷一個鏈表是否爲迴文結構

1. 題目描述(基礎要求)

給定一個鏈表的頭節點head,請判斷該鏈表是否爲迴文結構。 例如: 1->2->1,返回true。 1->2->2->1,返回true。15->6->15,返回true。 1->2->3,返回false。

2. 思路

如果對空間複雜度沒有要求的話,我們可以藉助輔助空間.我們藉助一個STL的stack將我們的value放到棧當中,然後對比的時候從棧頂彈出元素,如果有一個不相等則返回false,否則返回true; 進一步的話我們可以使用二個指針,一個快指針,一個慢指針,快指針一次走二步,慢指針一次走一步,當快指針到達終點的時候,慢指針剛好到達中點,然後我們將整個鏈表分成左和右二個部分,然後我們將右半部分壓棧進行對比,這樣就會節省一半的空間.

3. 進階版本

如果程序進一步要求:如果鏈表長度爲N,時間複雜度達到O(N),額外空間複雜度達到O(1)。也就是不準使用輔助空間,這個時候怎麼辦了?

  1. 首先用一個快指針,一個慢指針來遍歷鏈表。快指針每次走兩步,慢指針每次走一步。等到快指針遍歷完鏈表,慢指針就正好停留在鏈表的中央。
  2. 將鏈表的後半部分進行反轉。
  3. 將鏈表的前半部分與後半部分逐個比對。若都相同,則爲迴文鏈表,否則不是。
  4. 將反轉之後右半部分的鏈表進行恢復.

4. 代碼

4.1 程序說明:

這裏我們實現了三個函數進行判斷是否爲迴文鏈表,分別是:

  1. isPalindrome1 使用O(N)O(N)輔助空間,對應基礎版本.
  2. isPalindrome2 使用O(N/2)O(N/2)輔助空間,對應基礎版本.
  3. isPalindrome3 使用O(1)O(1)輔助空間,對應進階版本.
#include <iostream>
#include <vector>
#include <stack>

struct ListNode {
	int val;
	struct ListNode* next;
	ListNode(int x) :
			val(x), next(nullptr) {
	}
};
// need n extra space
bool isPalindrome1(ListNode* head) {
    std::stack<int> my_node_value;
    ListNode* curNode = head;
    while (curNode != nullptr) {
        my_node_value.push(curNode->val);
        curNode = curNode -> next;
    }

    while (head!= nullptr) {
        if (head -> val != my_node_value.top()) {
            return false;
        } else {
            head = head -> next;
            my_node_value.pop();
        }
    }
    return true;
}

// need n/2 extra space
bool isPalindrome2(ListNode* head) {
    if (head == nullptr || head -> next == nullptr) {
        return true;
    }
    std::stack<int> my_node_value;
    ListNode* slowNode = head -> next;
    ListNode* fastNode = head;
    while (fastNode -> next != nullptr && fastNode -> next -> next != nullptr) {    // get the middle node
        slowNode = slowNode -> next;
        fastNode = fastNode -> next -> next;
    }
    while (slowNode != nullptr) {
        my_node_value.push(slowNode -> val);
        slowNode = slowNode -> next;
    }
    while (!my_node_value.empty()) {   // here we can't use the condition: head != nullptr
        if (head -> val != my_node_value.top()) {
            return false;
            break;
        } else {
            head = head -> next;
            my_node_value.pop();
        }
    }
    return true;
}

// need O(1) extra space
bool isPalindrome3(ListNode* head) {
    if (head == nullptr || head -> next == nullptr) {
        return true;
    }
    ListNode* n1 = head;    // slow pointer
    ListNode* n2 = head;    // fast pointer
    while (n2 -> next != nullptr && n2 -> next -> next != nullptr) {
        n1 = n1 -> next;
        n2 = n2 -> next  -> next;
    }
    n2 = n1 -> next;    // n2 now is the first node in the second list
    n1 -> next = nullptr;
    ListNode* n3 = nullptr;    // A ListNode to store the last node in the second list
    while (n2 != nullptr) {
        n3 = n2 -> next;
        n2 -> next = n1;
        n1 = n2;
        n2 = n3;
    }
    n3 = n1;    // here n1 is the last node in the second list, we need to store the last node to reconver
    n2 = head;  // compare the first and the second list
    while (n1 != nullptr && n2 != nullptr) {
        if (n1 -> val != n2 -> val) {
            return false;
            break;
        } else {
            n1 = n1 -> next;
            n2 = n2 -> next;
        }
    }
    n1 = n3 -> next;    // here we recover the second list to the origin order
    n3 -> next = nullptr;   // the origin last node next poiter is nullptr
    while (n1 != nullptr) {
        n2 = n1 -> next;
        n1 -> next = n3;
        n3 = n1;
        n1 = n2;
    }
    return true;

}


void printList(ListNode* pHead) {
    while (pHead != nullptr) {
        std::cout << pHead -> val << ",";
         pHead= pHead -> next;
    }
    std::cout << "\n";
}

int main()
{
    ListNode* pHead = new ListNode(1);
    pHead -> next = new ListNode(2);
    pHead -> next -> next = new ListNode(1);
    std::cout << "origin list is:" << std::endl;
    printList(pHead);
    bool is_palindrome = isPalindrome3(pHead);
    if (is_palindrome) {
        std::cout << "is palindrome" << std::endl;
    } else {
        std::cout << "not palindrome" << std::endl;
    }
    return 0;
}

這裏的話我們列舉了二種情況:一種是1 2 1 結構,另外一種是 1 2 3 結構,我們都得到了正確的結果,這裏以isPalindrome3函數爲例子.
在這裏插入圖片描述

在這裏插入圖片描述

實現isPalindrome3函數還是有點複雜的,這個節點的指向有點繞暈了.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章