劍指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、算法思路
- 複製鏈表值到數組列表中。
- 使用雙指針法判斷是否爲迴文。
-
遍歷鏈表將值複製到數組列表中。用 currentNode 指向當前節點。每次迭代向數組添加 currentNode.val,並更新 currentNode = currentNode.next,當 currentNode = null 則停止循環。
-
在 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、思路
-
先判斷輸入的鏈表是否爲空的指針。如果第一個鏈表爲空,則直接返回第二個鏈表;如果第二個鏈表爲空,則直接返回第一個鏈表。如果兩個鏈表都是空鏈表,合併的結果是得到一個空鏈表。
-
兩個鏈表都是排序好的,我們只需要從頭遍歷鏈表,判斷當前指針,哪個鏈表中的值小,即賦給合併鏈表指針即可。使用遞歸就可以輕鬆實現。
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