题目描述:
给你单链表的头节点 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.了解链表:链表是一种线性结构,除了第一个和最后一个节点,其余节点都有一个前驱节点和一个后继节点,第一个只有后继,最后一个只有前驱。
2.了解题目的基本操作:既然涉及链表的整体反转,那么一定有遍历【即查找】,又因为没有出现数据的增删改,初步判断没有增删改。
3.模拟操作,选择比较特殊的几个数据:
1st.空数据,头节点为null:这个数据反转即原身
2nd.仅一个节点数据:反转也是原身。
3rd.两节点ab:反转为ba
4th.三节点abc:反转为cba
可以预想到,除了null,对于链表中的某个节点x,使其反转即x的指针域指向x-1的节点即可。其它的数据具有迭代性。
解题难点1分析:
经上分析,其实没发现很好的处理方法。
朴素的思想是:如果我们知道所有数据,与其次序关系,就可以很轻易解决。【比如:对于abc,我们有abc三个实例,并且知道原先的关系,那么直接c指向b,b指向a,a指向null即可】
问题1:如何做到?【length指链表长度】
借用ArrayList即可,while循环遍历一遍链表,把所有节点添加到ArrayList之中(由于添加的顺序一定,因此从0到length-1,ArrayList中数据和链表中的数据一致)
这时,用for循环遍历(只需从length-1,遍历到1即可,因为0下标的数据有点特殊)
代码如下,易知时间复杂度为O(2n),空间复杂度为O(n),效率不高。
代码1:
class Solution {
public ListNode reverseList(ListNode head) {
List<ListNode> temp = new ArrayList<ListNode>();
if(head==null){
return head;
}// 由于下面代码未处理特殊情况,所以在此处理【否则报错】
while(head!=null){
temp.add(head);
head=head.next;
}
for(int i=temp.size()-1; i>0; i--){
temp.get(i).next=temp.get(i-1);
}
temp.get(0).next=null;// 第一个节点指向null
return temp.get(temp.size()-1);
}
}
解题难点2分析:
代码1已经解决了问题,但是我们可以深入思考:
1.对于单个节点x,我们想使其反转,需要知道哪些信息?
只需要,前一个节点x-1的实例。
如果只用反转一个特定的节点,如此即可,不过我们需要从整个链表考虑。
2.我们反转了x,那么会出现什么情况?
数据丢失:第一,x的后继丢失(并且不可找回)。第二,形成环路:x与x-1形成环【当然,在迭代的角度,最后都会解环】
就2,其实我们可以知道,如果有个东西,可以指向x的后继,就能轻松迭代。
结合1、2,我们只要只要x的前驱x-1,x的后继x+1,就能不断反转链表。
代码2:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode now=head;// now指向需要反转的节点x
ListNode ptr=null;// x-1
ListNode next;// x+1
while(now!=null){
next=now.next;// 得到后继节点x+1,保证不丢失
now.next=ptr;// 反转
ptr=now;// 得到前驱节点x-1
now=next;// 前进一步
}
// 不处理head==null的原因:如果为null,不进入while,返回ptr==null
return ptr;
}
}
以上内容即我想分享的关于力扣热题7的一些知识。
我是蚊子码农,如有补充,欢迎在评论区留言。个人也是初学者,知识体系可能没有那么完善,希望各位多多指正,谢谢大家。