通常打印时一个只读操作,我们不希望打印时修改内容。假设面试官也要求这个题目不能改变链表的结构。
06:输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例1:
输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
方法一:reverse()反转
1.c++中的STL库中的begin(),end()用法
2.vector用法
3.reverse()用法
代码语言:cpp
/**
* 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) {
vector<int> res;
while (head){ //循环压入
res.push_back(head->val);
head = head->next;
}
reverse(res.begin(),res.end()); //反转
return res;
}
};
24 / 24 个通过测试用例
状态:通过
执行用时: 4 ms
内存消耗: 8.5 MB
- 时间复杂度 O(N)
- 空间复杂度 O(1)
方法二: 利用堆栈
思路:接下来我们要遍历链表。遍历的顺序是从头到尾的顺序,可输出的顺序却是从尾到头。也就是说第一个遍历到的结点最后一个输出,而最后一个遍历到的结点第一个输出。 这就是典型的“后进先出”,我们可以用栈实现这种顺序。每经过一个结点的时候,把该结点放到一个栈中。当遍历完整个链表后,再从栈顶开始逐个输出结点的值,此时输出的结点的顺序已经反转过来了。这种思路的实现代码如下:
代码语言:cpp
/**
* 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) {
vector<int> vec= {};
stack<ListNode*> s;
ListNode * node = head;
while(node!=NULL){ //循环将节点压入堆栈直到为空
s.push(node);
node = node->next;
}
while(!s.empty()){ //循环弹出,将栈顶元素压到vector后续输出
vec.push_back(s.top()->val);
s.pop();
}
return vec;
}
};
24 / 24 个通过测试用例
状态:通过
执行用时: 0 ms
内存消耗: 8.7 MB
1.堆栈:先进后出,后进先出。注意区分队列的区别,队列:先进先出。
- 时间复杂度 O(N): 入栈和出栈共使用 O(N) 时间
- 空间复杂度 O(N): 辅助栈
stack
和数组 vec 共使用 O(N) 的额外空间
方法三:简短递归法
既然想到了用栈来实现这个函数,而递归在本质上就是一个栈结构,于是很自然地又想到了用递归来实现。要实现反过来输出链表,我们每访问到一个结点的时候,先递归输出它后面的结点,再输出该结点自身,这样链表的输出结果就反过来了。基于这样的思路,不难写出如下代码:
代码语言:cpp
/**
* 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) {
if(!head)
return {};
vector<int> a=reversePrint(head->next); //直到指针为空时停止递归
a.push_back(head->val);
return a;
}
};
24 / 24 个通过测试用例
状态:通过
执行用时: 11 ms
内存消耗: 10.9 MB
- 时间复杂度 O(N): 遍历链表,递归 N 次
- 空间复杂度 O(N): 系统递归需要使用 O(N) 的栈空间