输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2] 输出:[2,3,1]给出链表的定义:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */刚开始想到用虚拟头结点指向尾部,一步步翻转过来,但是当时只想到用一个指针指向当前节点,苦于没有想到用另一个指针指向之前的节点,因此反转过程十分痛苦。这里就不上自己一半的代码了,下面看看网上好的解法与剑指上推荐的解法。网上解法来自公众号《代码随想录》。
人家的解法好就好在考虑问题比较全面,比如这道题,题目在没有明说是否能改变原链表的情况下,就要做两种考虑,可以改变链表与不改变链表;
顾名思义,就是直接把链表的指向改过来,原来的头结点变成尾节点,原来的尾节点现在变成头结点。这里用到双指针法,单个指针(指向当前节点)的解法很困难,因为单个指针确定不了当前节点的前一节点,这样当前节点改变指向不知道上一节点是谁。
class Solution_double_pointer {// 双指针法,会改变链表方向 public: vector<int> reversePrint(ListNode* head) { vector<int> res {}; ListNode *pre(nullptr); ListNode *cur = head; while (cur != nullptr) { // 记住当前节点的下一指向 ListNode *temp = cur->next; // 反转方向 cur->next = pre; // 双指针移动 pre = cur; cur = temp; } // 退出while循环条件:当前结点是尾节点指向的null,则pre就是尾节点 // 在逆序链表上顺序读取值 ListNode *recordPoint = pre; while (recordPoint != nullptr) { res.push_back(recordPoint->val); recordPoint = recordPoint->next; } return res; } };代码中注释已经很清楚了,双指针法最重要的就是要使用临时指针temp保存当前节点的下一节点,这样在当前节点cur的指向反转到上一节点pre后,能够移动双指针中的当前指针到下一节点上。
在不改变链表的前提下,我们每次遍历链表都是从前向后,但是题目要求的数值是链表从后向前遍历才能实现的。考虑到顺序反转,与栈的特性(先进后出)十分符合。可以使用一个额外空间的栈,保存各个节点,都保存进去以后,栈顶就是链表的尾节点,栈底是头结点,这样我们隐式地改变了链表的顺序。最后不断弹出栈顶节点并记录节点值,就可以完成题目要求。
这种方法的优点是:不会改变原链表结构
缺点是:需要额外的存储空间
class Solution_stack {// 栈记录节点,先进后出 public: vector<int> reversePrint(ListNode* head) { vector<int> res; stack<ListNode*> nodeValue; ListNode *cur = head; // 将节点存入栈中 while (cur != nullptr) { nodeValue.push(cur); cur = cur->next; } while (!nodeValue.empty()) { cur = nodeValue.top(); res.push_back(cur->val); nodeValue.pop(); } return res; } };这里的测试比较简单,链表无非就是多个节点、单节点、空链表这三种情况。
void test01() { ListNode x0 = 0; // x1->x2->x3 ListNode x1 = 1; ListNode x2 = 2; ListNode x3 = 3; x1.next = &x2; x2.next = &x3; cout << "x1 val = " << x1.val << endl; cout << "x1.next->val = " << x1.next->val << endl; cout << "x1.next->next->val = " << x1.next->next->val <<endl; Solution so; //多节点 vector<int> res_1 = so.reversePrint(&x1); for(auto e:res_1) cout << e << " "; cout << endl; //单节点 vector<int> res_2 = so.reversePrint(&x0); for(auto e:res_2) cout << e << " "; cout << endl; }