前言
久违的刷题计划开始了,本次计划为每日一题,路线如下:剑指offer(64题),HOT 100,精选算法 200。
问题
描述
输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。
如输入{1,2,3}的链表如下图:
返回一个数组为[3,2,1]
0 <= 链表长度 <= 10000
示例1
输入:
{
1,2,3}
返回值:
[3,2,1]
示例2
输入:
{
67,0,24,58}
返回值:
[58,24,0,67]
1. 思路
输入一个链表,返回该链表的反序。按元素先进后出的顺序,考虑借助栈。设一指针从头到尾遍历链表,边访问边入栈,直到指针遍历完链表后,将栈中各元素逐一出栈并输出。
2. 解决方案
c++解决方案:
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> output;
stack<int> s;
//链表不为空,指针从头到尾遍历链表
while(head!=NULL){
s.push(head->val);
head=head->next;
}
//栈不为空,弹栈
while(!s.empty()){
output.push_back(s.top());//保存栈顶元素
s.pop();//栈顶元素出栈
}
return output;
}
};
复杂度分析:
时间复杂度:O(n)。遍历链表是一个O(n),弹栈需要O(n)
空间复杂度:O(n)。栈空间最大长度是链表的长度n
3. 总结与反思
3.1 解法二 递归写法
由于这个题目需要我们从后面向前面开始打印这个数组。所以我们可以对遍历的结点进行一个递归,我们先递归到这个链表的最后面,然后不断向前收集权值。
思路
用DFS同样会遍历所有的结点,时间复杂度为O(n)
需要存储长度为n的链表的所有的结点,空间复杂度为O(n)
代码
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> ans;
void dfs(ListNode* now){
// 递归的出口为当前的指针为空的情况
if(!now){
return;
}
// 向后面进行递归
dfs(now->next);
// 递归之后收集权值
ans.push_back(now->val);
}
vector<int> printListFromTailToHead(ListNode* head) {
dfs(head);
return ans;
}
};
3.2 DFS相关补充知识
考研初试理论:
深度优先搜索(DFS:depth first search)
类似于树的先序遍历; DFS
所经历的边与顶点构成了深度优先生成树,遍历树中高度最高;
复杂度:空间:O(n),时间:邻接矩阵 O(n 2)、邻接表 O(n+e);
应用:判断图是否有环、图的连通性;