❓剑指 Offer 06. 从尾到头打印链表
难度:简单
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
💡思路:
法一:递归
要逆序打印链表 1->2->3(3,2,1):
- 可以先逆序打印链表 2->3(3,2),最后再打印第一个节点 1。
- 而链表 2->3 可以看成一个新的链表,要逆序打印该链表可以继续使用求解函数,也就是在求解函数中调用自己,这就是递归函数。
法二:栈
- 栈具有后进先出的特点,在遍历链表时将值按顺序放入栈中,最后出栈的顺序即为逆序。
法三:头插法
- 在遍历原始链表时,将当前节点插入新链表的头部,使其成为第一个节点。
为了能将一个节点插入头部,我们引入了一个辅助节点 h0
,该节点不存储值,只是为了方便进行插入操作。
(不要辅助节点与第一个节点混起来,第一个节点是链表中第一个真正存储值的节点。)
🍁代码:(C++、Java)
法一:递归
C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
private:
vector<int> ans;
public:
vector<int> reversePrint(ListNode* head) {
if(head != nullptr){
reversePrint(head->next);
ans.push_back(head->val);
}
return ans;
}
};
Java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
private ArrayList<Integer> tmp = new ArrayList<>();
public int[] reversePrint(ListNode head) {
revList(head);
int[] ans = new int[tmp.size()];
for(int i = 0; i < ans.length; i++){
ans[i] = tmp.get(i);
}
return ans;
}
void revList(ListNode head){
if(head != null){
revList(head.next);
tmp.add(head.val);
}
}
}
法二:栈
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> temp;
while(head != nullptr){
temp.push(head->val);
head = head->next;
}
vector<int> ans;
while(!temp.empty()){
ans.push_back(temp.top());
temp.pop();
}
return ans;
}
};
Java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int[] reversePrint(ListNode head) {
Stack<Integer> temp = new Stack<>();
while(head != null){
temp.add(head.val);
head = head.next;
}
int[] ans = new int[temp.size()];
for(int i = 0; i < ans.length; i++){
ans[i] = temp.pop();
}
return ans;
}
}
法三:头插法
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) {
ListNode* h0 = new ListNode;
while(head != nullptr){// 头插法构建逆序链表
ListNode* temp = head->next;
head->next = h0->next;
h0->next = head;
head = temp;
}
head = h0->next;
vector<int> ans;
while(head != nullptr){
ans.push_back(head->val);
head = head->next;
}
return ans;
}
};
Java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int[] reversePrint(ListNode head) {
int cnt = 0;
ListNode h0 = new ListNode(0);
while(head != null){// 头插法构建逆序链表
ListNode temp = head.next;
head.next = h0.next;
h0.next = head;
head = temp;
cnt++;
}
head = h0.next;
int[] ans = new int[cnt];
for(int i = 0; i < cnt; i++){
ans[i] = head.val;
head = head.next;
}
return ans;
}
}
🚀 运行结果:
🕔 复杂度分析:
- 时间复杂度: O ( n ) O(n) O(n),遍历一遍或两遍链表。
- 空间复杂度: O ( n ) O(n) O(n),法一和法二 额外使用一个栈存储链表中的每个节点;法三 仅使用常量级空间,所以为 O ( 1 ) O(1) O(1)。
题目来源:力扣。
放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我LeetCode主页 / CSDN—力扣专栏,每日更新!