1、题目描述
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
2、VS2019上运行
使用两个数组的方法
#include<iostream>
using namespace std;
#include<vector>
//定义单链表
struct ListNode {
int val;//表示节点的值
ListNode* next;//指向下一个节点的指针
//结构体中的构造函数定义;该构造函数接受一个整型参数,用于初始化节点的值。
//在构造函数的定义中,通过冒号初始化列表的方式对成员变量进行初始化
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
vector<int>reversePrint(ListNode* head) {
//临时向量temp用于存储正向顺序的链表节点值,答案向量ans用于存储逆序的链表节点值
vector<int> temp, ans;
//创建指针p,指向链表头节点
ListNode* p = head;
//temp存放正向的
while (p)
{
temp.push_back(p->val);//将当前节点的值存储在临时向量中
p = p->next;//移动到下一个节点
}
for (int i = temp.size() - 1; i >= 0; i--)
{
ans.push_back(temp[i]);//将临时向量中的值从后往前依次存储在答案向量中,实现逆序
}
return ans;
}
};
int main() {
// 创建一个简单的链表
ListNode* head = new ListNode(1);
ListNode* second = new ListNode(2);
ListNode* third = new ListNode(3);
head->next = second;
second->next = third;
Solution solution;
vector<int> result = solution.reversePrint(head);
// 打印结果数组
for (int num : result) {
cout << num << " ";
}
cout << endl;
}
运行结果
3 2 1
3、多种方法实现
(1)方法一:使用两个数组实现
- 定义两个向量(动态数组),将链表中的节点的值按照从头到尾的顺序(使用一个循环)遍历到tmp向量中,然后逆序(从后往前)遍历tmp向量,将其中的元素依次添加到ans向量中。
- 注意:数组的大小可以通过size()函数来获得,但是链表通常需要遍历整个链表才能确定其大小,比如:
// 计算链表大小的函数
int getListSize(ListNode* head) {
int size = 0;
ListNode* current = head;
while (current != nullptr) {
size++;
current = current->next;
}
return size;
}
- 使用两个向量vector实现从尾到头打印链表:
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int>tmp,ans;
ListNode*cur=head;
while(cur!=nullptr){
tmp.push_back(cur->val);
cur=cur->next;
}
for(int i=tmp.size()-1;i>=0;i--){
ans.push_back(tmp[i]);
}
return ans;
}
};
(2)方法二:使用一个数组+reverse函数翻转
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int>ans;
ListNode*cur=head;
while(cur!=nullptr){
ans.push_back(cur->val);
cur=cur->next;
}
reverse(ans.begin(),ans.end());
return ans;
}
};
(3)方法三:使用递归方法
- 递归:递归是一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。因此递归过程,最重要的就是查看能不能讲原本的问题分解为更小的子问题,这是使用递归的关键
- 本题递归的终止条件是当前节点为空(即指针为nullptr),这时函数不再递归调用自身,而是直接返回到上一级递归调用处,然后继续执行打印操作。
- 如果不返回数组的话,直接打印出来:
void reversePrint(ListNode* head) {
if (head == nullptr)
return;
reversePrint(head->next);
cout << head->val <<endl;//逆序打印链表
}
- 但是本题要求返回数组,所以递归函数里再加一个参数向量ans,然后再加一个函数用来返回数组(没有想到把两个函数结合在一起的方法,就用的力扣官方的题解)
显式返回:
class Solution {
public:
void recursion(ListNode* head, vector<int>&ans) {//ans向量必须引用传递(如果不加引用,就是按值传递,那么每次递归调用都会创建一个新的ans副本,而不是在原始的ans上操作
if(head==nullptr){
return;
}
recursion(head->next,ans);
ans.push_back(head->val);
}
vector<int> printListFromTailToHead(ListNode* head) {
vector<int>ans;
recursion(head, ans);
return ans;
}
};
隐式返回:
因为void函数没有返回值,可以隐式返回
class Solution {
public:
void recursion(ListNode* head, vector<int>& res){
if(head != nullptr){
recursion(head->next, res);
res.push_back(head->val);
}
}
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> res;
recursion(head, res);
return res;
}
};
(4)方法四:栈
(利用栈先进后出的性质,其实许多递归问题都可以通过改成栈来变成等价的迭代)
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
stack<int> s; // 一个辅助栈
vector<int> res;//存储结果
while (head != nullptr) {
// 先按顺序加入栈中
s.push(head->val);
head = head->next;
}
while (!s.empty()) {
// 按照栈的pop顺序加入结果中
res.push_back(s.top());
s.pop();
}
return res;
}
};
4、vector中常用的容器函数
vector 容器是 C++ 标准库中的一个动态数组容器,提供了多个函数用于操作和管理其中的元素。下面是一些常用的 vector 容器函数:
1、元素访问:
- operator[]:通过索引访问容器中的元素。
- at:通过索引访问容器中的元素,提供越界检查。
- front:返回容器的第一个元素的引用。
- back:返回容器的最后一个元素的引用。
- data:返回指向容器底层数据的指针。
2、迭代器:
- begin:返回指向容器首元素的迭代器。
- end:返回指向容器尾元素的下一个位置的迭代器。
- rbegin:返回指向容器尾元素的反向迭代器。
- rend:返回指向容器首元素前一个位置的反向迭代器。
3、容量管理:
- size:返回容器中元素的数量。
- empty:检查容器是否为空。
- resize:改变容器的大小。
- capacity:返回容器当前可容纳的元素数量。
- reserve:增加容器的容量以容纳指定数量的元素。
4、添加和删除元素:
- push_back:在容器尾部添加一个元素。
- pop_back:移除容器中的最后一个元素。
- insert:在指定位置插入一个或多个元素。
- erase:从指定位置或指定范围内删除一个或多个元素。
- clear:移除容器中的所有元素。
5、其他操作:
- assign:将容器的内容更改为新的指定值或指定范围的值。
- swap:交换两个容器的内容。
- emplace:在指定位置构造一个元素。
- emplace_back:在容器尾部构造一个元素。
- reverse:翻转容器中的元素(逆序排列)
5、stack中常用的函数(5个)
- push():将元素压入栈顶。
- pop():弹出栈顶元素,但不返回其值。
- top():返回栈顶元素的引用,但不弹出该元素。
- empty():检查栈是否为空,返回一个布尔值。
- size():返回栈中元素的数量。