❓剑指 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—力扣专栏,每日更新!


















