剑指offer之面试题5:从尾到头打印链表

本文介绍了三种方法从尾到头打印链表的值:利用ArrayList进行两次遍历,使用栈的后进先出特性,以及通过递归实现。分别提供了对应的Java代码实现,并指出在不考虑线程安全情况下,ArrayDeque是栈的良好选择。
摘要由CSDN通过智能技术生成

题目描述

输入一个链表,从尾到头打印链表每个节点的值。
输入描述:

输入为链表的表头

输出描述:

输出为需要打印的“新链表”的表头

思路1:new一个临时的ArrayList(temp),遍历一遍链表,将链表的每个值顺序放进temp中;new一个新的ArrayList(list),遍历一遍temp,通过list.get(list.size()-1-i)获取倒序的链表元素,并顺序放进list中。最后返回list。

下面贴出根据这一思路编写的代码,已在牛客OJ提交成功

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
public class Solution {
    public static ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> temp=new ArrayList<Integer>();
        //put list to new list
        while(listNode!=null){
            temp.add(listNode.val);
            listNode=listNode.next;
        }
        ArrayList<Integer> list=new ArrayList<Integer>();
        for(int i=0;i<temp.size();i++){
            list.add(temp.get(temp.size()-i-1));
        }
        return list;
    }
    public static void main(String[] args){
        ArrayList list=new ArrayList();
        list.add(new ListNode(1));
        list.add(new ListNode(2));
        list.add(new ListNode(3));
        list.add(new ListNode(4));
        list.add(new ListNode(5));
        for(int i=0;i<list.size();i++){
            ListNode listNode=(ListNode)list.get(i);
            if(i+1<list.size()){
                listNode.next=(ListNode)list.get(i+1);
            }
        }
        ListNode root=(ListNode)list.get(0);
        System.out.println(printListFromTailToHead(root));
    }
}

思路2:后进先出,这是栈的工作原理,所以可以考虑用栈来实现,扫描一个结点时,把该结点push进栈中,直到扫描完所有结点元素,然后通过pop逐个去除栈顶元素打印,则打印出的顺序就是从尾到头。

根据以上思路,贴出实现代码,牛客网OJ提交成功

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public static ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        Stack<Integer> stack=new Stack<Integer>();
        while(listNode!=null){
            stack.push(listNode.val);
            listNode=listNode.next;
        }
        ArrayList<Integer> list=new ArrayList<Integer>();
        while(!stack.empty()){
            list.add(stack.pop());
        }
        return list;
    }
    public static void main(String[] args){
        ArrayList list=new ArrayList();
        list.add(new ListNode(1));
        list.add(new ListNode(2));
        list.add(new ListNode(3));
        list.add(new ListNode(4));
        list.add(new ListNode(5));
        for(int i=0;i<list.size();i++){
            ListNode listNode=(ListNode)list.get(i);
            if(i+1<list.size()){
                listNode.next=(ListNode)list.get(i+1);
            }
        }
        ListNode root=(ListNode)list.get(0);
        System.out.println(printListFromTailToHead(root));
    }
}

查看Stack的API,会发现栈的实现推荐使用ArrayDeque。

Deque 接口及其实现提供了 LIFO 堆栈操作的更完整和更一致的 set,应该优先使用此 set,而非此类。例如: 

   Deque<Integer> stack = new ArrayDeque<Integer>();
Deque 接口的大小可变数组的实现。数组双端队列没有容量限制;它们可根据需要增加以支持使用。它们不是线程安全的;在没有外部同步时,它们不支持多个线程的并发访问。禁止 null 元素。此类很可能在用作堆栈时快于 Stack,在用作队列时快于 LinkedList。

在不考虑线程安全的情况下,用ArrayDeque实现从尾到头打印链表的代码如下,在牛客OJ提交成功

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
import java.util.ArrayDeque;
public class Solution {
    public static ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayDeque<Integer> stack=new ArrayDeque<Integer>();
        while(listNode!=null){
            stack.push(listNode.val);
            listNode=listNode.next;
        }
        ArrayList<Integer> list=new ArrayList<Integer>();
        while(!stack.isEmpty()){
            list.add(stack.pop());
        }
        return list;
    }
    public static void main(String[] args){
        ArrayList list=new ArrayList();
        list.add(new ListNode(1));
        list.add(new ListNode(2));
        list.add(new ListNode(3));
        list.add(new ListNode(4));
        list.add(new ListNode(5));
        for(int i=0;i<list.size();i++){
            ListNode listNode=(ListNode)list.get(i);
            if(i+1<list.size()){
                listNode.next=(ListNode)list.get(i+1);
            }
        }
        ListNode root=(ListNode)list.get(0);
        System.out.println(printListFromTailToHead(root));
    }
}

思路3:既然可以用栈实现,而递归本质上就是一个栈,故想到用递归实现。遍历链表结点,先打印结点后面的结点,在打印该结点。
用递归的思想实现代码如下,已被牛客网AC

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
public class Solution {
    public static ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> list=new ArrayList<Integer>();
        if(listNode!=null){
            if(listNode.next!=null){
                list=printListFromTailToHead(listNode.next);
            }
            //System.out.print(listNode.val+" ");
            list.add(listNode.val);
        }
        return list;
    }
    public static void main(String[] args){
        ArrayList list=new ArrayList();
        //ListNode node=new ListNode();
        list.add(new ListNode(1));
        list.add(new ListNode(2));
        list.add(new ListNode(3));
        list.add(new ListNode(4));
        list.add(new ListNode(5));
        for(int i=0;i<list.size();i++){
            ListNode listNode=(ListNode)list.get(i);
            if(i+1<list.size()){
                listNode.next=(ListNode)list.get(i+1);
            }
        }
        ListNode root=(ListNode)list.get(0);
        //System.out.println(root.next.val);
        //printListFromTailToHead(root);
        System.out.println(printListFromTailToHead(root));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值