劍指Offer之鏈表系列:從尾到頭打印鏈表、反轉鏈表、迴文鏈表、合併兩個排序的鏈表(C++和Python實現)

劍指Offer(三):從尾到頭打印鏈表

輸入一個鏈表的頭節點,從尾到頭反過來返回每個節點的值(用數組返回)。

示例 1:

輸入:head = [1,3,2]
輸出:[2,3,1]

1、思路

通常,這種情況下,我們不希望修改原鏈表的結構。返回一個反序的鏈表,這就是經典的“後進先出”,我們可以使用棧實現這種順序。每經過一個結點的時候,把該結點放到一個棧中。當遍歷完整個鏈表後,再從棧頂開始逐個輸出結點的值,給一個新的鏈表結構,這樣鏈表就實現了反轉。

2、代碼
  • C++:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        stack<int> result;
        vector<int> reverse;
        ListNode* nodes = head;
        while(nodes !=NULL){
            result.push(nodes->val);
            nodes = nodes->next;
        }
        while(!result.empty()){
            reverse.push_back(result.top());
            result.pop();
        }
        return reverse;

    }
};
  • Python實現:
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
 
class Solution:
    def printListFromTailToHead(self, listNode):
        # write code here
        result = []
        while listNode:
            result.insert(0, listNode.val)
            listNode = listNode.next
        return result

劍指Offer(十五):反轉鏈表

反轉一個單鏈表。

示例:

輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL

1、思路
  • 這個很簡單,我們使用三個指針,分別指向當前遍歷到的結點、它的前一個結點以及後一個結點。
  • 在遍歷列表時,將當前節點的 next 指針改爲指向前一個元素.
2、代碼
  • C++:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pReversedHead = NULL;
        ListNode* pNode = head;
        ListNode* pPrev = NULL;
        while(pNode != NULL){
            ListNode* pNext = pNode->next;
            if(pNext == NULL){
                pReversedHead = pNode;
            }
            pNode->next = pPrev;
            pPrev = pNode;
            pNode = pNext;
        }
        return pReversedHead;
    }
};
  • python:
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head
        last = None

        while head:
            tmp = head.next
            head.next = last
            last = head
            head = tmp
        return last

LeetCode 234. 迴文鏈表

請判斷一個鏈表是否爲迴文鏈表。

示例 1:

輸入: 1->2
輸出: false

示例 2:

輸入: 1->2->2->1
輸出: true

1、算法思路
  • 複製鏈表值到數組列表中。
  • 使用雙指針法判斷是否爲迴文。
  1. 遍歷鏈表將值複製到數組列表中。用 currentNode 指向當前節點。每次迭代向數組添加 currentNode.val,並更新 currentNode = currentNode.next,當 currentNode = null 則停止循環。

  2. 在 Python 中,很容易構造一個列表的反向副本,也很容易比較兩個列表。因此最好使用雙指針法來檢查是否爲迴文。我們在起點放置一個指針,在結尾放置一個指針,每一次迭代判斷兩個指針指向的元素是否相同,若不同,返回 false;相同則將兩個指針向內移動,並繼續判斷,直到相遇。

在編碼的過程中,注意我們比較的是節點值的大小,而不是節點本身。正確的比較方式是:node_1.val == node_2.val。而 node_1 == node_2 是錯誤的。

2、複雜度分析
  • 時間複雜度:O(n),其中 n 指的是鏈表的元素個數。
    • 第一步: 遍歷鏈表並將值複製到數組中,O(n)。
    • 第二步:雙指針判斷是否爲迴文,執行了 O(n/2)次的判斷,即 O(n)。
    • 總的時間複雜度:O(2n) = O(n)。
  • 空間複雜度:O(n),其中 n 指的是鏈表的元素個數,我們使用了一個數組列表存放鏈表的元素值。
3、代碼實現:
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        vals = []
        current_node = head
        while current_node is not None:
            vals.append(current_node.val)
            current_node = current_node.next
        return vals == vals[::-1]

劍指Offer(十六):合併兩個排序的鏈表

輸入兩個單調遞增的鏈表,輸出兩個鏈表合成後的鏈表,當然我們需要合成後的鏈表滿足單調不減規則。

1、思路
  1. 先判斷輸入的鏈表是否爲空的指針。如果第一個鏈表爲空,則直接返回第二個鏈表;如果第二個鏈表爲空,則直接返回第一個鏈表。如果兩個鏈表都是空鏈表,合併的結果是得到一個空鏈表。

  2. 兩個鏈表都是排序好的,我們只需要從頭遍歷鏈表,判斷當前指針,哪個鏈表中的值小,即賦給合併鏈表指針即可。使用遞歸就可以輕鬆實現。

2、代碼實現
  • C++:
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        //判斷指針是否爲空
        if(pHead1 == NULL){
            return pHead2;
        }
        else if(pHead2 == NULL){
            return pHead1;
        }
        ListNode* pMergedHead = NULL;
        if(pHead1->val < pHead2->val){
            pMergedHead = pHead1;
               pMergedHead->next = Merge(pHead1->next, pHead2);
        }
        else{
            pMergedHead = pHead2;
               pMergedHead->next = Merge(pHead1, pHead2->next);
        }
        return pMergedHead;
    }
};
  • Python:
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合併後列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if not pHead1:
            return pHead2
        if not pHead2:
            return pHead1
        pMergeHead = None
        if pHead1.val < pHead2.val:
            pMergeHead = pHead1
            pMergeHead.next = self.Merge(pHead1.next, pHead2)
        else:
            pMergeHead = pHead2
            pMergeHead.next = self.Merge(pHead1, pHead2.next)
        return pMergeHead
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章