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

本文介绍了多种方法来从尾到头打印链表,包括使用动态数组、两次遍历以及栈。每种方法的时间复杂度和空间复杂度都进行了分析,并强调了解决链表问题时递归和栈的优先考虑。此外,还提供了递归和栈的具体实现代码,以及优化思考。
摘要由CSDN通过智能技术生成

1.题目

剑指 Offer 06. 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

示例 1:

输入:head = [1,3,2]
输出:[2,3,1]

限制:

0 <= 链表长度 <= 10000

2.思路与实现

1.动态数组
依次读取链表中每个值并将其存入动态数组中,创建一个与动态数组大小相同的数组,遍历动态数组,将值反序存入数组
时间N
空间N
引入额外数据结构

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] reversePrint(ListNode head) {
        ArrayList<Integer> res = new ArrayList<>();
        while(head != null)
        {
            res.add(head.val);
            System.out.println(head.val);
            head = head.next;
        }
        int[] arr = new int[res.size()];
        int j = arr.length - 1;
        for(Integer i : res)
        {
            arr[j--] = i;
        }
        return arr;
        

    }
}

可能可以优化的地方:

  • 动态数组的存在一方面记录元素的数量,一方面记录元素的值,首先想到如果直接知道链表的长度,一次遍历链表即可
  • 这个链表是简化的,没有size()方法,因此需要想办法知道链表的长度
  • 先遍历一次得到长度,再遍历一次得到值
  • 但问题存在于,遍历一次后,head就代表最后一个节点,所以需要在第一次遍历前就将head存储起来

2.两次遍历
时间N
空间N
不引入额外数据结构
速度最快

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] reversePrint(ListNode head) {
        ListNode temp = head;
        int len = 0;
        while(temp != null)
        {
            len++;
            temp = temp.next;
        }
        int[] arr = new int[len];
        int i = len - 1;
        while(head != null)
        {
            arr[i--] = head.val;
            head = head.next;
        }
        return arr;

    }
}

3.总结思路与实现

其他方法
3.递归法:在走至链表末端的过程中统计链表,到达末端时利用已知的长度创建数组,回溯时依次将元素存入数组
时间n
空间n
不引入额外数据结构

class Solution {
    int[] res;
    int i;
    int j;
    public int[] reversePrint(ListNode head) {
        solve(head);
        return res;

    }
    public void solve(ListNode head)
    {
        if(head == null)
        {
            res = new int[i];
            return;
        }
        i++;
        solve(head.next);
        res[j] = head.val;
        j++;

    }
}
  • 注意,递归法也可以使用动态数组实现,但引入额外数据结构

4.栈
利用栈的后进先出原则,将节点值压入栈,利用栈的大小创建数组,再进行出栈操作并存储数值
N
N

class Solution {
    
    public int[] reversePrint(ListNode head) {
        Stack<Integer> stack = new Stack<>();
        while(head != null)
        {
            stack.push(head.val);

            head = head.next;
        }
        int size = stack.size();
        int[] res = new int[size];            
        for(int i = 0; i < size; i++)//不可使用size(),因为栈在压出后大小会减一
        {
            res[i] = stack.pop();
        }
        return res;

    }
    
}

4.相关知识

  • 解决链表问题优先思考1递归和2栈,3将递归优化为循环
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值