目录
题目链接:反转链表
一.题目要求
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
提示:
链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000
二.解题思路
1.使用迭代法
首先,我们要逆置该链表,最先想到的肯定是需要循环遍历该链表。
ListNode cur=head;
while(cur!=null){
cur=cur.next;
}
然后在循环遍历的基础上,对结点进行逆置。
如果我们想改变cur到下一个结点的引用,使其指向cur的前一个结点,那我们就要提前记录下cur的前一个结点(prev),从而改变cur的引用,成功后使cur和prev都向后移动。
这时我们可以发现一个问题,在cur.next=prev时,cur的下一步引用就被改变了,是指向prev的,比如在这张图中,2逆置后就指向1,不再指向3,接下来的cur=cur.next不会使cur从2变到3,那我们如何使cur向后移动呢?
我们可以新建一个结点(next)先指向cur.next,最后再使cur=next即可。
考虑头结点和尾结点的情况:
头结点成立:
尾结点成立:
并且由此可见,我们最后返回的链表头结点应该是prev。
如想了解链表(LinkedList)相关知识,请查阅:
2.使用栈结构
首先,我们要知道栈的结构特点是 "先进先出" ,如果想要逆序链表,那我们可以先将链表结点一个一个 "压栈" ,等所有结点都入栈后,再一个一个 "出栈" 即可,这样就实现了链表的逆序。
需要注意的是:
(1).本题要求返回的类型是ListNode类型,也就是头结点(start),所以需要我们新建一条链表,并且新建一个移动结点(tmp),由于我们需要进行tmp=tmp.next的解引用操作,所以我们新建的不能是空链表。
ListNode start=new ListNode(0,ListNode(0));
ListNode tmp=start;
(2).那么为什么一开始进入循环后就要使tmp.next=stack.pop()呢?为什么不能使tmp=stack.pop()?
这是为了和反转的是空链表的情况统一,所以将第一个结点(start)设置为工具结点,从(start.next)才开始操作,所以最后需要返回的是start.next。
while(!stack.isEmpty()){
tmp.next=stack.pop();
tmp=tmp.next;
}
return start;
(3).循环结束后要将tmp.next=null,也就是将尾结点的下一个设置为null,防止链表中出现环。
tmp.next=null;
3.使用递归思想
首先我们要思考递归最后结束的条件是什么,第一种情况是链表是个空链表,即head==null;第二种情况就是head移动到尾结点,即head.next=null,这两种情况时返回head(经历递归函数的话会变为newHead),否则对下一个结点进行逆置操作。
if(head==null||head.next==null){
return head;
}
所以,调用递归函数的顺序是从head开始向后(调用时刷新逆序后的新结点newHead),那么进行逆序的顺序是从倒数第一个结点开始,依次向前进行结点的逆序操作。
ListNode newHead=reverseList(head.next);
具体的逆序操作是怎样的呢?
我们可以记录下前驱结点(ListNode prev=head)和当前结点(ListNode cur=head.next),然后使当前结点指向前驱结点(cur.next=prev),然后一定要使前驱结点的指向为null(prev.next=null),否则逆置后的链表可能会产生环。
//记录前驱结点
ListNode prev=head;
//记录当前结点
ListNode cur=head.next;
//使当前结点指向前驱结点
cur.next=prev;
//使前驱结点的指向为空
prev.next=null;
三.具体代码
1.使用迭代法
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur=head;
ListNode prev=null;
while(cur!=null){
ListNode next=cur.next;
cur.next=prev;
prev=cur;
cur=next;
}
return prev;
}
}
2.使用栈结构
class Solution {
public ListNode reverseList(ListNode head) {
Deque<ListNode> stack=new LinkedList<>();
ListNode cur=head;
while(cur!=null){
ListNode e=cur;
stack.push(e);
cur=cur.next;
}
ListNode start=new ListNode(0,ListNode(0));
ListNode tmp=start;
while(!stack.isEmpty()){
tmp.next=stack.pop();
tmp=tmp.next;
}
tmp.next=null;
return start;
}
}
3.使用递归思想
class Solution {
public ListNode reverseList(ListNode head) {
//从后向前递归逆转
//空链表 或 到达链表结尾 返回
if(head==null||head.next==null){
return head;
}
//逆转下一个结点
ListNode newHead=reverseList(head.next);
//记录前驱结点
ListNode prev=head;
//记录当前结点
ListNode cur=head.next;
//使当前结点指向前驱结点
cur.next=prev;
//使前驱结点的指向为空
prev.next=null;
return newHead;
}
}
四.运行截图
1.使用迭代法
2.使用栈结构
3.使用递归思想
如有建议或想法,欢迎一起讨论学习~