一、前言
大家好,本文章属于《剑指 Offer 每日一题》中的系列文章中的第 4 篇。
在该系列文章中我将通过刷题练手的方式来回顾一下数据结构与算法基础,同时也会通过博客的形式来分享自己的刷题历程。如果你刚好也有刷算法题的打算,可以互相鼓励学习。我的算法基础薄弱,希望通过这两三个月内的时间弥补这块的漏洞。本次使用的刷题语言为 Java ,预计后期刷第二遍的时候,会采用 Python 来完成。
- 刷题平台: leetcode 的剑指 Offer 专题
- 码云仓库地址
二、题目
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
三、解题思路
3.1 思路1:递归法
利用递归先走到链表末端,然后回溯时依次将节点值加入列表,这样就可以实现链表值的倒序输出。
- 1、递归阶段:每次传入 head.next ,以 head == null 为递归终止条件,此时直接返回
- 2、回溯阶段:层层回溯时,把当前节点加入列表
- 3、将列表转为数组返回。
3.1.1 代码
class Solution {
ArrayList<Integer> tmp = new ArrayList<Integer>();
public int[] reversePrint(ListNode head) {
recur(head);
int [] nums =new int[tmp.size()];
for (int i = 0; i < tmp.size(); i++) {
nums[i]=tmp.get(i);
}
return nums;
}
private void recur(ListNode head) {
if(head ==null) return ;
recur(head.next);
tmp.add(head.val);
}
}
3.1.2 执行效果
3.1.3 复杂度分析
可以看到递归的执行效果是很差的,特别是在数据量上来之后,既有进去的过程,也会有回溯的时间性能浪费。
- 时间复杂度:O(n),遍历链表,递归N次
- 空间复杂度:O(N),使用O(N)的空间来存储
3.2 思路2:数组反向填值
单向链表的特点就是不能从尾节点遍历到头节点,但是数组就可以。数组也可以反向填充值,因此,我们可以在获取到链表的长度之后,new 一个同等大小的数组,反向填充值即可。
3.2.1 代码实现
class Solution {
public static int[] reversePrint(ListNode head) {
// 1、首先我们要知道链表的长度
int count=0;
ListNode node =head;
while (node!=null){
++count;
node=node.next;
}
//2、建造一个nums数组
node=head;
int[] nums =new int[count];
for (int i = count-1; i >=0 ; i--) {
nums[i]=node.val;
node=node.next;
}
return nums;
}
}
3.2.2 执行效果
3.2.3 复杂度分析
本题主要少了递归的遍历,但是还是需要遍历原来的链表长度,并遍历了两次,没有浪费额外的空间。
- 时间复杂度:O(N)
- 空间复杂度:O(1)
四、总结
本题是遇到的第一个链表题,链表的结构在面试中是非常重要的,它的结构很简单,由指针将若干个节点连接成链状结构。
链表的创建、插入节点、删除节点操作只需要几十行的代码就能实现,这些基础知识都需要掌握的,但是平常工作中可能很少用到这个结构,都是用现成的 api 来实现。所以,关于链表的写法需要自己有意练习。
本题主要对单链表做了简单的考察,需要自己课后弥补链表的相关写法。
今天的刷题就到这了,欢迎点赞评论交流,剑指 Offer 刷题之旅将继续展开!