题目描述:
输入一个链表,按链表值从尾到头的顺序返回一个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)。
注意第二种思路可能存在递归层次太深而导致栈溢出的风险。