题目来源:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/
Problem
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2] 输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
Idea
考察链表、堆(或数组)的基本操作
栈API:next,val
数组创建:int[] arr = new int[maxLend]
Solution1
递归。在输出当前值之前,调用本身去查找栈的下一个数
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
private int[] arr = new int[10000];
private int index = 0;
private void getNext(ListNode head) {
if (head == null) {
return;
}
getNext(head.next);
arr[index] = head.val;
index = index + 1;
}
public int[] reversePrint(ListNode head) {
getNext(head);
int[] rArr = new int[index];
for (int i =0; i < index; i++){
rArr[i] = arr[i];
}
return rArr;
}
}
执行用时:1 ms, 在所有 Java 提交中击败了73.56%的用户
内存消耗:39.9 MB, 在所有 Java 提交中击败了13.17%的用户
可以看到效果并不好
Solution2
思路与Solution1相同,但在得到链表长度时才声明数据。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
private int[] arr;
private int index = 0;
private int maxIndex = 0;
private void getNext(ListNode head) {
if (head == null) {
arr = new int[maxIndex];
return;
}
maxIndex = maxIndex+1;
getNext(head.next);
arr[index] = head.val;
index = index + 1;
}
public int[] reversePrint(ListNode head) {
getNext(head);
return arr;
}
}
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:40.1 MB, 在所有 Java 提交中击败了10.38%的用户
有意思的是,这种声明方式对内存的开销影响并不大,反而是执行时间缩短了。看来在对于系统而言,分配存储的时间远比分配内存的代价要大。
Solution3
用链表存储数据,最后将链表转为数组。
class Solution {
ArrayList<Integer> tmp = new ArrayList<Integer>();
public int[] reversePrint(ListNode head) {
recur(head);
int[] res = new int[tmp.size()];
for(int i = 0; i < res.length; i++)
res[i] = tmp.get(i);
return res;
}
void recur(ListNode head) {
if(head == null) return;
recur(head.next);
tmp.add(head.val);
}
}
执行用时:2 ms, 在所有 Java 提交中击败了43.02%的用户
内存消耗:40.7 MB, 在所有 Java 提交中击败了5.08%的用户
结果消耗的时空都比简单的数组要大,看来堆的使用场景不在小数据上。
Solution4
利用栈后进先出的特征,存储数据,最后转为数组返回。
class Solution {
public int[] reversePrint(ListNode head) {
Stack<ListNode> stack = new Stack<ListNode>();
ListNode temp = head;
while (temp != null) {
stack.push(temp);
temp = temp.next;
}
int size = stack.size();
int[] print = new int[size];
for (int i = 0; i < size; i++) {
print[i] = stack.pop().val;
}
return print;
}
}
执行用时:1 ms, 在所有 Java 提交中击败了73.56%的用户
内存消耗:39.5 MB, 在所有 Java 提交中击败了49.07%的用户
并无明显优化。
Rethink
想提升效率,就降低数组声明次数与声明时间。