1. 程式人生 > >LeetCode連結串列篇C++ [逆序、迴文、逆序II]

LeetCode連結串列篇C++ [逆序、迴文、逆序II]

1. 關鍵點

  • 結點定義
//Definition for singly-linked list.
 struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

迴圈過程如下:

next = head->next;
head->next = prev;
prev = head;
head = next;

初始條件為“` prev = NULL;
迭代停止條件為 head == NULL

2. 建立連結串列

ListNode* create()
{
    ListNode* pHead, *pNode, *temp;
    int
x; pHead = pNode = (ListNode*)malloc(sizeof(ListNode)); //帶頭節點的連結串列 // 先把第一個結點做了。 printf("請輸入連結串列資料,以小於0 的為結束標誌:\n"); scanf("%d", &x); pNode->val = x; pNode->next = NULL; scanf("%d", &x); while (x>=0) { temp = (ListNode*)malloc(sizeof(ListNode)); temp->val = x; temp->next = NULL; pNode->next = temp;//上一個結點指向當前新建立的結點
pNode = temp; scanf("%d", &x); } pNode->next = nullptr; return pHead; }

3. 實現逆序

ListNode* ReverseLink(LINK_NODE *head)
  {
       ListNode *next;
       ListNode *prev = NULL;
       while(head != NULL)
      {
          next = head->next;
          head->next
= prev; prev = head; head = next; } return prev; //返回的是prev }

4. 判斷迴文

1 2 3 4 5 5 4 3 2 1 -> 是迴文

同樣藉助上面的逆序的方法,採用龜兔演算法
- 【234. Palindrome Linked List】
迴文連結串列的特點就是對稱,那麼要判斷是否迴文就可以用兩個指標指向對稱的節點,看裡面的資訊是否一樣。即對稱的位置是否有對稱的資訊。由於是單向連結串列,不能同時用兩個指標從頭尾向內部遍歷取值比較。那麼就考慮從連結串列中間開始,用兩個指標向兩頭遍歷取值比較,顯然這也需要進行連結串列逆置。

(1). 獲取連結串列的中點,使用龜兔演算法的方法,兩個指標,一個遍歷速度是另外一個的兩倍,找到中點
(2). 然後反轉連結串列的後半部分
(3). 對比連結串列的前後兩個部分是否一樣
(4). 最後將原連結串列的後半部分反轉恢復原來的連結串列(恢復作案現場)

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if (!head || !head->next) return true;
        ListNode *slow = head, *fast = head;
        while (fast->next && fast->next->next) {
            slow = slow->next;//slow 每次移動一個
            fast = fast->next->next;//fast 每次移動2位
        }
        ListNode *last = slow->next, *pre = head;
        ListNode* prev = NULL;
        while (last != NULL) //這裡就是前面的逆序部分
        {
            ListNode* tmp = last->next;
            last->next = prev;
            prev = last;
            last = tmp;
        }
        while (prev) //一一與正序的進行比較
        {
            if (prev->val != pre->val) 
                return false;//只要有不相等,提前結束
            prev = prev->next;
            pre = pre->next;
        }
        return true;
    }
};

5. 部分逆序

  • 只翻轉從m到n部分的連結串列
    Input: 1->2->3->4->5->NULL, m = 2, n = 4
    Output: 1->4->3->2->5->NULL
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        int L = 0;//total length
        ListNode* result = NULL;
        ListNode* pre = head;
        ListNode* prev = head;
        while (pre != NULL)
        {
            L++;
            pre = pre->next;//求總長度用
        }   
        if (m > n || m < 1 || n < 1 || m > L || n > L)
            return NULL; //不滿足條件,返回NULL
        if (m == n)
            return head;// 不翻轉
        for (int i = 1; i < m; i++)
            prev = prev->next;//此時的prev之後的需要逆轉

        ListNode* result2 = head;
        ListNode* Next;
        ListNode* PreNode = NULL; //用來記錄前一個結點
        ListNode* Now = prev; //需要反轉的結點

        for (int i = m; i <= n; i++) //從m到n, 進行反轉,與上面的逆序操作一樣
        {
            Next = Now->next;
            Now->next = PreNode;//反轉
            PreNode = Now;
            Now = Next;
        }

        int u = 1;
        ListNode* result3 = head;//最後要返回的結果儲存
        while (u < m-1 && result2->next !=NULL)
        {
            u++;
            result2 = result2->next;//獲取不變的第一部分
        }

        if (m == 1)
        {
            result3 = PreNode;//從第一個開始的話,就沒有前面了部分了。
        }
        else
        {
            result2->next = NULL;
            result2->next = PreNode;//接上第二部分
        }

        ListNode* tmp2 = result3;
        u = 1;
        while (u < n )
        {
            tmp2 = tmp2->next;
            u++;
        }
        if (tmp2 != NULL)
            tmp2->next = Now;//接上第三部分
        return result3;
    }
};