学习交流加

  • 个人qq:
    1126137994
  • 个人微信:
    liu1126137994
  • 学习交流资源分享qq群:
    962535112

牛客网题目链接:
从尾到头打印链表

文章目录

  • 题目描述
  • 1、递归解法
    • 1.1、 递归解法一
      • java代码:
      • C++代码
      • 分析:
    • 1.2 递归解法二
      • java代码:
      • C++代码
  • 2、使用栈
    • java代码
    • C++代码
  • 总结

题目描述

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

本题较为简单。有两种解法:递归和使用栈循环。

1、递归解法

递归解法,也可以有两种写法。

1.1、 递归解法一

先上代码,下面给解释:

java代码:

import java.util.ArrayList;
public class Solution {ArrayList<Integer> arrayList=new ArrayList<Integer>();//注意这个ArrayList必须在方法体外定义public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {if(listNode!=null){this.printListFromTailToHead(listNode.next);arrayList.add(listNode.val);}return arrayList;}
}

C++代码

class Solution {public:vector<int> res;//注意这个vector必须在成员函数外定义vector<int> printListFromTailToHead(ListNode* head) {if(head!=nullptr){this->printListFromTailToHead(head->next);res.push_back(head->val);}return res;}
};

分析:

这种递归的写法,可以这么想:因为想要从尾到头打印链表,那么如果此链表为空,则直接返回。如果只有一个节点,则将此节点打印。否则,递归打印头结点以后的节点,直到递归到最后一个节点,那么,因为最后一个节点后面为空,所以返回上一级调用,上一级调用后的代码为res.push_back(head->val);,此时的head刚好指向的最后的节点,将最后一个节点先放到数组。然后又返回到上一级的调用,将倒数第二个节点放到数组中。以此类推,直到将第一个节点放到数组中。

我们可以看如下图示来分析上述递归的过程:


1.刚开始head指向节点1,不为空,将head指针指向下一个节点,然后递归调用函数到第2步


2.此时head依然不为空,将head指针指向下一个节点,然后递归调用函数到第3步


3.此时head依然不为空,将head指针指向下一个节点,然后递归调用函数到第4步


4.此时head依然不为空,将head指针指向下一节点,然后递归调用函数第5步


5.此时head指向空,递归结束,那么递归结束后,就需要返回到上一个递归的步骤,上一步骤是步骤4,那么执行递归语句的下一句:res.push_back(head->val)
(C++代码),节点4的值放到数组中。然后再返回到步骤3,将节点3的值放入数组。以此类推,最终从后往前将所有链表节点的值放到数组中。

注意:此种递归方法中,返回数组的定义一定要放在函数体外面定义,如果放在函数体内定义,那么由于递归的层级不同,就会导致每次递归的时候都会重新定义一个数组,导致最后我们只能将第一个节点的值返回,结果肯定是错的。在下一种递归的方法中,返回数组是可以定义在函数体内的,原因见下面解释。

1.2 递归解法二

java代码:

import java.util.ArrayList;
public class Solution {public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {ArrayList<Integer> resArray = new ArrayList<>();if(listNode != null){if(listNode.next != null)resArray = printListFromTailToHead(listNode.next);resArray.add(listNode.val);}return resArray;}
}

C++代码

class Solution {public:vector<int> printListFromTailToHead(ListNode* head) {vector<int> res;if(head!=nullptr){if(head->next!=nullptr)res = printListFromTailToHead(head->next);res.push_back(head->val);}return res;}
};

分析: 这种递归,实际上更好理解。首先,如果链表位空,则直接返回空数组。如果链表只有一个节点,则直接返回这个节点的值。如果这个链表不止一个节点,那么递归调用函数得到除了头结点外后面的链表,得到后面的链表的从后往前打印(放到数组)的结果,然后再将之前的头结点打印(放到数组末尾)。那么,最终得到的结果就是整个链表的从后往前打印的结果。

可以简单的以下面图示理解:
1.
刚开始,head指向头结点,它后面还有节点(具体有几个都无所谓)。将head指向下一个节点,然后递归调用函数。


2.现在是这样的,从第1步过来,该递归调用函数求现在的这个链表的从后往前打印的结果。我们把现在这剩下的具有三个节点的链表,看成一个黑匣子整体,我的函数要对这个黑匣子求解它的倒序,然后这个函数返回了该链表的倒序的结果{4,3,2}。(其实这里面有好几个递归的过程,但是我们不必将所有的递归过程想出来,只需要知道,现在我们可以将后面剩余的链表看成一个新链表,然后得到它的倒序就行)

3.得到后面的链表的倒序后,是存入数组的,最后我们再将头结点的值,放到数组末尾res.push_back(head->val);,就可以得到{4,3,2,1},这正是我们要的结果。

注意:这里的递归解法中,返回数组的定义,可以放到函数体内,也可以放到函数体外。与第一种递归的不同之处在于,这里我们可以将以下两句话,放在同一个调用栈内看待,即
res =
printListFromTailToHead(head->next);这句话得到后面的链表的倒序后,就执行res.push_back(head->val);它们的执行,可以看成是在一个函数调用栈内进行的。而第一种递归调用中如果将返回数组定义在函数体内,每一个调用都是在一个新的函数调用栈,导致每一个函数栈中,都是一个新的返回数组,最终只能得到最顶层的函数栈中的数组,也就是链表的头结点的值。

2、使用栈

递归解法虽然写法简单,但是递归调用需要重新开辟函数调用栈,开销比较大。正常的解法实际上是使用栈来解决(栈这种数据结构本身就与递归有很大的联系)。

可以遍历链表,每遍历一个节点就将节点的值压入到栈中,直到遍历完链表。最后再依次将栈中的元素弹出到返回的数组中。

java代码

import java.util.Stack;
import java.util.ArrayList;
public class Solution {public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {Stack<Integer> st = new Stack<>();ListNode pListNode = listNode;while(pListNode != null){st.push(pListNode.val);pListNode = pListNode.next;}ArrayList<Integer> resArray = new ArrayList<>();while(!st.isEmpty()){resArray.add(st.pop());}return resArray;}
}

C++代码

class Solution {public:vector<int> printListFromTailToHead(ListNode* head) {vector<int> res;stack<int> st;ListNode* p = head;while(p != nullptr){st.push(p->val);p = p->next;}int len = st.size();for(int i = 0;i<len;++i){res.push_back(st.top());st.pop();}return res;}
};

总结

  • 理解递归的精髓,上述两种递归的不一样之处
  • 理解递归与栈的关系

学习探讨加:
qq:1126137994
微信:liu1126137994

【剑指offer - C++/Java】3、从尾到头打印链表相关推荐

  1. 剑指Offer - 九度1511 - 从尾到头打印链表

    剑指Offer - 九度1511 - 从尾到头打印链表2013-11-29 21:08 题目描述: 输入一个链表,从尾到头打印链表每个节点的值. 输入: 每个输入文件仅包含一组测试样例. 每一组测试案 ...

  2. 剑指offer面试题[5]-从尾到头打印链表

    目描述 输入一个链表,从尾到头打印链表每个节点的值. /** *  struct ListNode { *        int val; *        struct ListNode *next ...

  3. 【剑指offer】登峰造极之从尾到头打印链表

    题目链接 从尾到头打印链表. 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M 热度指数:1254529 题目描述 /** struct ListNode { i ...

  4. 剑指Offer - 面试题6. 从尾到头打印链表(栈,递归,反转链表)

    文章目录 1. 题目 2. 解题 2.1 stack解题 2.2 递归 2.3 反转链表 1. 题目 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回). 示例 1: 输入:head ...

  5. 剑指offer 面试题5—从尾到头打印链表

    题目: 输入一个链表的头结点,从尾到头反过来打印出每个结点的值. 考虑用栈 public void invertedList1(ListNode head) {if (head == null) {r ...

  6. 剑指offer(C++)-JZ6:从尾到头打印链表(数据结构-链表)

    作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 题目描述: 输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回). 如输入{ ...

  7. 剑指offer面试题06. 从尾到头打印链表(辅助栈法)

    题目描述 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回). 思路 详见链接 代码 class Solution:def reversePrint(self,head:ListNod ...

  8. 【剑指offer-Java版】05从尾到头打印链表

    从头到尾打印链表:递归实现比较简单 注意处理异常输入:如输入指针为空 处理边界条件等即可 public class _Q05 {public static void main(String[] arg ...

  9. JAVA实现从尾到头打印链表(《剑指offer》)

    最近在刷<剑指offer>里的编程题,但是网上关于<剑指offer>的解答多半是C或者C++的,而且官方(作者)也是在用C++进行讲解,这里自己用java写了一些题目的解答代码 ...

  10. 剑指Offer(Java实现)把二叉树打印成多行

    题目描述 从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行. 解题思路 利用辅助空间链表或队列来存储节点,每层输出. 代码实现 import java.util.ArrayList; i ...

最新文章

  1. 通知:正式迁移至新博客
  2. wex5 转换 html5,WeX5开发工具(html5 app开发框架)V3.9 开源版
  3. 林绪虹:看好QoE、音视频内容理解与AV1
  4. Debian7 apt源设置
  5. t-mobile频段_T-Mobile再次被黑客入侵:超过200万个帐号和地址可能泄漏
  6. ARCGIS 拓扑规则阐述
  7. c++歌手类代码_安卓资源ID修改-游戏发行-切包过程中的R类和Public.xml
  8. 使用折半查找法查找数组中的元素
  9. Microsoft Office/visio/Project 2013 with SP1 简体中文零售版
  10. [js高手之路]Node.js模板引擎教程-jade速学与实战1-基本用法
  11. python3 mysql插入数据冲突
  12. 吃货在东京 -- 记那段吃不饱的日子 之二 丰州的雪花牛肉
  13. edm邮件html模板,EDM模板使用说明
  14. 有道单词导入 大量有道单词 生词本 批量导入 添加 有道单词XML 背单词
  15. TensorFlow机器翻译之moses切词(附:ActivePerl安装)
  16. 【Python】定时获取卫星地球图像作为电脑壁纸
  17. 2022-2027年中国B2C电子商务行业市场深度分析及投资战略规划报告
  18. 智能卡脚本语言easyCard
  19. latex中的三种字体格式
  20. C语言large函数的作用,LARGE函数简介

热门文章

  1. 第六十八期:做中台找死,不做中台等死?
  2. 第十九期:程序员节,女朋友偷偷送了我这个...
  3. 11集成计划的制定与实施
  4. java学习(62):java抽象类
  5. Qt中的TableWidget初始化表头、行高、选中、自动扩展和接受修改
  6. JS中完美兼容各大浏览器的scrolltop方法
  7. 关于Android回调的理解
  8. 1-2docker-基本的使用
  9. python之yield的一些应用
  10. verilog 除法器