剑指 Offer 06. 从尾到头打印链表

解题思路一:栈

使用栈,遍历链表时,将每个节点对应的val值存储到栈中

因为栈是一种LIFO的数据结构,我们依次将栈顶元素添加至返回数组res,直至栈清空

返回res

代码

Java

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public int[] reversePrint(ListNode head) {
  11. Stack<Integer> stack = new Stack<>();
  12. int len = 0;
  13. while(head != null){
  14. stack.push(head.val);
  15. head = head.next;
  16. len++;
  17. }
  18. int[] res = new int[len];
  19. int i = 0;
  20. while(!stack.isEmpty()){
  21. res[i++] = stack.pop();
  22. }
  23. return res;
  24. }
  25. }

复杂度分析

  • 时间复杂度:O(N)

我们需要从头至尾遍历链表,并且将栈清空,相当于遍历了两次链表,时间复杂度为:O(N)

  • 空间复杂度:O(N)

我们额外使用了栈这种数据结构来存储链表每个节点值,额外空间复杂度为:O(N)
_

解题思路二:使用列表List

使用一个List列表,在遍历链表时,将链表每个节点的值存储在List

使用

  1. Collections.reverse(list);

反转列表

使用Java8引入的stream将列表转换成数组

  1. list.stream().mapToInt(Integer::valueOf).toArray();

代码

Java

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public int[] reversePrint(ListNode head) {
  11. List<Integer> list = new ArrayList<>();
  12. while(head != null){
  13. list.add(head.val);
  14. head = head.next;
  15. }
  16. Collections.reverse(list);
  17. return list.stream().mapToInt(Integer::valueOf).toArray();
  18. }
  19. }

复杂度分析

  • 时间复杂度:O(N)

无论是遍历链表,调用 Collections.reverse() 方法,还是将 list 转化为 int 数组,时间复杂度均为:O(N)

  • 空间复杂度:O(N)

我们使用了一个 arraylist 存放链表的 val 值,所以额外空间复杂度为:O(N)
_

解题思路三:反转链表

双指针法反转链表,使用一个变量 size 记录链表的长度,这样是为了能够开辟返回数组,最后遍历反转之后的链表,将每个节点对应的 val 值存储到返回数组中。

代码

Java

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public int[] reversePrint(ListNode head) {
  11. ListNode pre = null;
  12. ListNode next = null;
  13. int size = 0;
  14. while(head != null){
  15. next = head.next;
  16. head.next = pre;
  17. pre = head;
  18. head = next;
  19. size++;
  20. }
  21. int[] res = new int[size];
  22. int i = 0;
  23. while(pre != null){
  24. res[i++] = pre.val;
  25. pre = pre.next;
  26. }
  27. return res;
  28. }
  29. }

复杂度分析

  • 时间复杂度:O(N)

遍历两次链表,时间复杂度为:O(N)

  • 空间复杂度:O(1)

我们在反转链表时,只是用了有限的几个变量,所以额外空间复杂度为:O(1)