1 思路:先遍历链表,用一个数组存储链表的值。然后反转该数组,返回该数组即可。
2 核心模块
①遍历链表
我的误区:head是虚拟头结点,不存放有意义的链表数据。
按照题目意思:head中存放链表的第一个数据。
遍历链表:定义指向ListNode类型的指针p,使其指向头结点。仅当p不为空的时候,将p的数据域存入数组,并且将p指向下一个节点。最后返回数组。对应代码:
ListNode * p=head;
while(p!=NULL)
{
Ldata.push_back(p->val);
p=p->next;
}
极端情况说明:如果传入的链表为空,则不进行任何操作,直接返回数组。因为数组仅声明,所以输出为空。
②反转数组
反转数组有三种实现方式:
方式一:自定义实现反转,注意千万不要在数组本身上反转,会覆盖会出错,再定义一个新的数组,将反转后的结果存入新数组。
for(int i=0;i<Ldata.size();i++)
res.push_back(Ldata[Ldata.size()-1-i]);
return res;
方式二:使用algorithm中的reverse()函数,注意reverse函数传入的参数
reverse(Ldata.begin(),Ldata.end());
return Ldata;
方式三:使用vector中的反转迭代器
vector <int> ::reverse_iterator rit=Ldata.rbegin();
for(;rit!=Ldata.rend();rit++)
res.push_back(*rit);
return res;
3 完整代码
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector <int> Ldata,res;
ListNode * p=head;
while(p!=NULL) //对于头指针的理解有问题,头指针也可以存放链表的有效数据
{
Ldata.push_back(p->val);
p=p->next;
}
//法一:自定义自己实现反转的时候千万不要在数组本身上反转,会覆盖会出错
//for(int i=0;i<Ldata.size();i++)
// res.push_back(Ldata[Ldata.size()-1-i]);
// return res;
//法二:使用algorithm中的reverse()函数
//reverse(Ldata.begin(),Ldata.end());
// return Ldata;
//法三:使用vector中的反转迭代器
vector <int> ::reverse_iterator rit=Ldata.rbegin();
for(;rit!=Ldata.rend();rit++)
res.push_back(*rit);
return res;
}
};
4 收获:
在线编程题如果只有一部分通过率,不一定是没考虑到边界情况,还有可能是逻辑上存在错误。
5 新思路:
vector的成员函数push_back和insert插入方式的差异:push_back()在数组尾部插入元素 & insert()在某个位置前插入某个或者某区间元素。push_back对应尾插法,最后得到的是相同顺序序列,insert选择每次在首元素前面插入新元素,对应头插法,最后得到的相反顺序的序列。所以本题可以用insert每次在首元素前面插入元素直接得到相反顺序的序列。
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector <int> Ldata,res;
ListNode * p=head;
while(p!=NULL)
{
Ldata.insert(Ldata.begin(),p->val);
p=p->next;
}
return Ldata;
}
};
6 收获
①声明类和结构体 后面不需要加(),但是末尾需要加;
②对于<剑指Offer>这种有函数定义的题目,你只要完成函数,返回相关的值就可以,不需要处理任何输入输出,不要在函数里输出任何东西。用好传给你的参数,返回指定类型的返回值就好,不要有多余的输入输出。这也体现了“封装”的思想。
③vector不能直接用cout输出,需要迭代器或者循环。
vector只声明,没有添加任何元素,迭代器输出的结果为空。