题目的主要信息:

  • 输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值
  • 返回值保存在vector的数组中

方法一:递归

具体做法:
我们都知道递归到底层后才会往上,因此我们可以递归遍历链表,将填充数组放到递归函数后面,就可以实现遍历到链表最后再逐渐往前将值填到数组中。

class Solution {
public:
    void recursion(ListNode* head, vector<int>& res){ //递归函数
        if(head != NULL){
            recursion(head->next, res); //先往链表深处遍历
            res.push_back(head->val); //再填充到数组就是逆序
        }
    }
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> res;
        recursion(head, res); //递归打印
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,递归遍历一次链表
  • 空间复杂度:,递归栈的空间为链表长度

方法二:栈

具体做法:
递归的思想也可以用栈实现,递归本质上就是用栈实现的。我们可以顺序遍历链表,将链表的值push到栈中,然后再依次弹出栈中的元素,加入到数组中。
图片说明

class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> res;
        stack<int> s;
        while(head != NULL){ //正序输出链表到栈中
            s.push(head->val);
            head = head->next;
        }
        while(!s.empty()){ //输出栈中元素到数组中
            res.push_back(s.top());
            s.pop();
        }
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,遍历链表是一个,弹空一个栈需要
  • 空间复杂度:,栈空间最大长度是链表的长度

方法三:反转数组

具体做法:
题目只需要最后输出的数组是链表的逆序,那我们可以顺序遍历链表,依次输入到链表中,最后用reverse函数将数组反转即可。

class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> res;
        while(head != NULL){ //正序输出到数组中
            res.push_back(head->val);
            head = head->next;
        }
        reverse(res.begin(), res.end()); //函数反转数组
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,一次遍历,reverse函数复杂度也是
  • 空间复杂度:,res属于返回函数必要空间,不属于额外空间

方法四:逆序填充数组

具体做法:
这种方法的思想是输入到数组中的值按照下标的逆序来输入,这样一来我们就要先确定vector数组有多大,可以先遍历一次链表得到链表长度也即是数组长度。然后从数组最后的下标开始按顺序填充链表中的值即可。

class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        int n = 0;
        ListNode* p = head; //遍历的指针
        while(p != NULL){ //统计链表长度
            n++;
            p = p->next;
        }
        vector<int> res(n, 0); //限定返回数组的大小
        p = head;
        while(p != NULL){ //遍历链表
            res[n - 1] = p->val; //数组上逆序记录
            p = p->next; //链表往后
            n--; //下标往前
        }
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,统计长度一次遍历,填充数组一次遍历
  • 空间复杂度:,res属于返回函数必要空间,无额外空间使用