第3题 从尾到头打印链表

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/H_233/article/details/87884752

题目描述:

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


解析思路:

题目意思就是逆序输出一个链表,需要以ArrayList的形式返回,也就是说ArrayList中存储的是逆序后链表中每个节点的值。

第一种思路:

关键在于逆序链表,说到逆序,我们不难想到栈这种数据结构,它的特点就是先进后出。那么问题就很简单了,我们只需要顺序遍历链表,将每个节点的值压入栈(push)中,然后再遍历栈,每次弹出(pop)时add进ArrayList中即可。

代码如下(Java版):

注意已给出ListNode类,val代表当前节点的值,next代表对下一节点的引用。

/**
*    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 ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        //初始化一个栈
        Stack<Integer> stack = new Stack();
        while (listNode != null) {
            //如果当前节点有下一个节点,压到栈中,并跳到下一个节点
            stack.push(listNode.val);
            listNode = listNode.next;
        }
        //初始化一个ArrayList
        ArrayList<Integer> list = new ArrayList<>();
        while (!stack.empty()) {
            //将栈中的内容全部弹出到list中
            list.add(stack.pop());
        }
        return list;
    }
}

这种思路,它的时间复杂度为O(n),常数系忽略。

第二种思路:

我们可以通过递归实现,递归的开始条件:只要下一节点不为null,就递归;递归的结束条件:下一节点为null;方法始终完成的内容:向List中添加当前节点的值并返回添加后的list;如果满足递归条件,那么初始化list为下层返回的list,否则不满足递归条件,返回一个新的list。也就是说持续递归到最后一个节点,然后将值add到list中,然后返回list。这样的话,就到达了一个逆序add的效果。例如有3个节点的链表,那么会递归2次,最后一次方法调用会将最后一个节点的值add到list中,并返回该list,然后第2次方法调用拿到该list,再将第二个节点的值add其中,依次类推。具体Java代码如下:

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> list;
        //排除特殊情况
        if (listNode == null) {
            list = new ArrayList<>();
            return list;
        }
        //如果当前节点的下一节点不为null,则继续递归,然后将当前节点的值add到下层返回的list中,否则add到一个新list中
        if (listNode.next != null) {
            list = printListFromTailToHead(listNode.next);
        } else {
            list = new ArrayList<>();
        }
        list.add(listNode.val);
        return list;
    }
}

但是上述代码有两个问题,(1)每一次方法调用都会初始化一个局部引用变量,空间浪费(2)除了第一次方法调用外,接下来的递归调用,listNode == null 的判断就是多余的,因为上一次调用已经判断过了(listNode.next != null)。所以有了如下的优化:

将局部变量提出,维护一个成员变量即可;将递归条件变成:当前节点不为null,就递归下一节点并add值到list中,否则直接返回list。

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

这种递归思路,它的时间复杂度为O(n)。

注意第二种思路可能存在递归层次太深而导致栈溢出的风险。 

猜你喜欢

转载自blog.csdn.net/H_233/article/details/87884752