力扣206(java&python)-反转链表(简单)
题目:
给你单链表的头节点 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
进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
本题与:剑指offer24.反转链表 一样
解题思路:
一、双指针(迭代)
设立两个指针节点,一个cur指向,初始指向head,一个pre,初始指向null,并设立一个临时节点temp用于保存cur的下一个节点,循环遍历链表,当cur为null时表示没有后续结点存在,停止循环,循环内做的事:
- 保存cur的下一个结点,存在temp中:temp = cur.next;
- 将当前cur的下一个指针指向pre:cur.next = pre;
- pre向前移动一位:pre = cur;
- cur向前移动一位:cur = temp
最后返回pre。
注意:为啥要先移动pre再移动cur,如果先先移动cur,cur = temp,pre的值再变为cur这时cur的值已经变了。
java代码:
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode() {} 7 * ListNode(int val) { this.val = val; } 8 * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 * } 10 */ 11 class Solution { 12 public ListNode reverseList(ListNode head) { 13 //申请两个指针,一个指向头结点一个指向空 14 ListNode cur = head; 15 ListNode pre = null; 16 //设置一个临时变量来保存cur的下一个结点 17 ListNode temp = null; 18 //当cur为空表示没有后续结点时停止循环 19 while(cur != null){ 20 temp = cur.next; 21 cur.next = pre; 22 //将pre和cur前进一位 23 pre = cur; 24 cur = temp; 25 } 26 return pre; 27 } 28 }
python3代码:
1 # Definition for singly-linked list. 2 # class ListNode: 3 # def __init__(self, val=0, next=None): 4 # self.val = val 5 # self.next = next 6 class Solution: 7 def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: 8 cur = head 9 pre = None 10 11 while cur: 12 temp = cur.next 13 cur.next = pre 14 pre = cur 15 cur = temp 16 17 return pre
二、递归
递归看图解很好理解,但是看代码不是很好理解~ 参考@王尼玛大佬的题解和官方题解下各位大佬的注解
递归的两个条件:
- 终止条件是当前节点或者下一个节点为null(head == null || head.next == null)
- 在函数内部,改变节点的指向,即 head 的下一个节点指向 head :head.next.next = head
递归函数中每次返回的 cur 其实只是最后一个节点,在递归函数内部,改变的是当前节点的指向。
递归本质是栈,从尾部向前构造,这里出栈要做的事就是建立反向连接并删除正向连接。
举例:1-->2-->3-->4-->5
第一轮:首先一直递归,直到遇到5时,下一个结点为空了,就返回结点5,此时head = 5,head.next = null;
第二轮:head为4,head.next为5,执行head.next.next=head,即5.next = 4
-
把当前节点的子节点的子节点指向当前节点,把5指向4;
-
此时链表为1->2->3->4<->5,由于4与5互相指向,所以此处要断开,即4.next=null;
-
此时链表为1->2->3->4<-5;
-
返回节点5
第三轮出栈:head为3,head.next为4,执行head.next.next=head,即4.next =3
-
把当前节点的子节点的子节点指向当前节点,把4指向3;
-
此时链表为1->2->3<->4<-5,由于3与4互相指向,所以此处要断开,即3.next=null;
-
此时链表为1->2->3<-4<-5;
-
返回节点5
第四轮出栈:head为2,head.next为3,执行head.next.next=head,即3.next =2
-
把当前节点的子节点的子节点指向当前节点,把3指向2;
-
此时链表为1->2<->3<-4<-5,由于2与3互相指向,所以此处要断开,即2.next=null;
-
此时链表为1->2<-3<-4<-5;
-
返回节点5
第五轮出栈:head为1,head.next为2,执行head.next.next=head,即2.next =1
-
把当前节点的子节点的子节点指向当前节点,把2指向1;
-
此时链表为1<->2<-3<-4<-5,由于1与2互相指向,所以此处要断开,即1.next=null;
-
此时链表为1<-2<-3<-4<-5;
-
返回节点5
出栈完成,最终头结点5->4->3->2->1
注意:这里的newhead结点5,就相当于于从1楼爬上五楼拿了一个苹果,然后又从5楼下楼,每下一层楼就展示一下这个苹果。
java代码:
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode() {} 7 * ListNode(int val) { this.val = val; } 8 * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 * } 10 */ 11 class Solution { 12 public ListNode reverseList(ListNode head) { 13 //设置终止条件 14 if(head == null || head.next == null) return head; 15 //递归传入下一结点,到达尾结点 16 ListNode newHead = reverseList(head.next); 17 head.next.next = head; 18 head.next = null; 19 20 return newHead; 21 } 22 }
python3代码:
1 # Definition for singly-linked list. 2 # class ListNode: 3 # def __init__(self, val=0, next=None): 4 # self.val = val 5 # self.next = next 6 class Solution: 7 def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: 8 if not head or not head.next: 9 return head 10 11 newHead = self.reverseList(head.next) 12 13 head.next.next = head 14 head.next = None 15 16 return newHead
2023-05-03日补充
递归(根据双指针的思路写出)
1 //递归 2 class Solution { 3 public ListNode reverseList(ListNode head) { 4 if (head == null) return null; 5 return reverse(head, null); 6 } 7 public ListNode reverse(ListNode cur, ListNode pre){ 8 if (cur == null) return pre; 9 ListNode temp = cur.next; 10 cur.next = pre; 11 return reverse(temp, cur); 12 } 13 }
栈:
1 //使用栈 2 class Solution { 3 public ListNode reverseList(ListNode head) { 4 //处理特殊情况 5 if (head == null) return null; 6 if (head.next == null) return head; 7 //定义一个栈,让所有节点入栈 8 Stack<ListNode> stack = new Stack<>(); 9 ListNode cur = head; 10 while (cur != null){ 11 stack.push(cur); 12 cur = cur.next; 13 } 14 //出栈 15 //设置一个虚拟头结点 16 ListNode dummyHead = new ListNode(0); 17 cur = dummyHead; 18 while (!stack.isEmpty()){ 19 ListNode node = stack.pop(); 20 cur.next = node; 21 cur = cur.next; 22 } 23 cur.next = null; 24 return dummyHead.next; 25 } 26 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)