描述
2021年,新年第二天,吃过晚饭,没想到一道简简单单的题把我卡了半天,于是乎记录一下。建议自己先写写试试。
题目:
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
链表结构:
class ListNode{
int val;
ListNode next;
public ListNode(int val){
this.val = val;
}
}
public ListNode reverseList(ListNode head) {
//实现代码
}
其实开始想法是遍历链表,用栈保存其中的int值,然后再从栈中取出int生成新的链表。确实可以实现,但是效率太低,肯定不是最优的。最后再贴出栈的实现方法。
递归
相信不少同学和我一样,遇到递归的问题总是很头疼,而一看解答,却发现大佬们几行递归代码就优雅的解决了问题。遇到递归问题很容易进入思维误区,所谓递归,程序反复调用自身即是递归。既然能够调用自身说明它每一级的功能都是一样的,因此我们只需要关注一级递归的解决过程即可。
递归把握好三个关键点就可以了:
- 找整个递归的终止条件:递归应该在什么时候结束?
- 找返回值:应该给上一级返回什么信息?
- 本级递归应该做什么:在这一级递归中,应该完成什么任务?
这里推荐一个博客,写的非常清晰,套路解决递归问题
对于该题分析:
终止条件:节点为空或者它的下一个节点为空
返回值:返回给上一级已经反转完成的链表
本级应该做什么:反转后面的节点,并且将当前节点插入到它后面节点的后面
class Solution {
public ListNode reverseList(ListNode head) {
//终止条件
if(head == null || head.next == null){
return head;
}
//将后面的节点反转
ListNode next = reverseList(head.next);
//将当前节点插入它后面的节点
head.next.next = head;
//防止产生循环链表
head.next = null;
return next;
}
}
记得上学时候数据结构老师告诉我们,关于链表的操作,一定要在纸上把过程先画出来,再写程序。不过这次画翻车了,这里记录下我进入的误区,因为head.next.next = head这行让我想了好久,画图表示一下当时我的理解:
假设当前传入的是2节点,假设它后面已经反转完成,所以画出了上面的图,而我一直再想怎么让5去指向2,想着想着就迷路了。这里就是一个思维误区了,下意识的以为2就是已经指向了5,但是实际应该是下面这样:
实际上2指向的是3节点,因为2的next并没有变啊,这样再看head.next.next = head是不是就瞬间明白了。而head.next = null;也懂了吧,就是防止3指向2,2又指向3。
迭代
一般来说递归能够实现的迭代也可以,可以使用双指针,也可以使用栈。先说双指针:
考虑遍历链表,并在访问各节点时修改 next 引用指向:
class Solution {
public ListNode reverseList(ListNode head) {
//记录前一个节点用的
ListNode pre = null;
//从头节点开始
ListNode cur = head;
//临时记录下一个节点
ListNode temp = null;
while(cur != null){
//记录下一个节点
temp = cur.next;
//将当前节点指向上前节点,实现反转
cur.next = pre;
//将当前节点交给pre,为下一次的循环做准备
pre = cur;
//移动到下一个节点
cur = temp;
}
return pre;
}
}
具体思路已经加到注释上了,不再赘述了,看下时间:
栈是一种先进后出的数据结构,下面是使用栈来实现反转,思路就是遍历保存到栈中,再遍历栈,生成新的链表:
class Solution {
public ListNode reverseList(ListNode head) {
Stack<Integer> stack = new Stack<>();
while(head != null){
stack.add(head.val);
head = head.next;
}
ListNode temp = new ListNode(0),result = temp;
while(stack.size() != 0){
temp.next = new ListNode(stack.pop());
temp = temp.next;
}
return result.next;
}
}
栈没啥好说的大家随便看看,果然耗时最长。
记录完毕。
岁月流逝忽已暮,皆因惆怅不知路。
2021年加油吧,打工人!