链表3:反转链表(206)

本题如下:(链接:https://leetcode.cn/problems/reverse-linked-list/)

题目:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例: 输入: 1->2->3->4->5->NULL       输出: 5->4->3->2->1->NULL

 

思路:对于这道题只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表,如下图所示:

 

可见,之前链表的头节点是元素1, 反转之后头结点就是元素5 ,这里并没有添加或者删除节点,仅仅是改变next指针的方向。

那么具体的实施步骤就是,首先要定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。

在反转前要先把 cur->next 节点用tmp指针保存一下,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。

接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。

最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时return pre指针就可以了,pre指针就指向了新的头结点。

 

具体的C++代码如下:

双指针法:

复制代码
 1 class Solution {
 2 public:
 3     ListNode* reverseList(ListNode* head) {
 4         ListNode* temp; // 保存cur的下一个节点
 5         ListNode* cur = head;
 6         ListNode* pre = NULL;
 7         while(cur) {
 8             temp = cur->next;  // 保存一下 cur的下一个节点,因为接下来要改变cur->next
 9             cur->next = pre; // 翻转操作
10             // 更新pre 和 cur指针
11             pre = cur;
12             cur = temp;
13         }
14         return pre;
15     }
16 };
复制代码

 

递归法1:

递归法虽然看起来相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。

关键是在于初始化的地方,可以看到双指针法中初始化 cur = head,pre = NULL,在递归法中可以从如下代码看出初始化的逻辑也是一样的,只不过写法变了。

复制代码
 1 class Solution {
 2 public:
 3     ListNode* reverse(ListNode* pre,ListNode* cur){
 4         if(cur == NULL) return pre;
 5         ListNode* temp = cur->next;
 6         cur->next = pre;
 7         // 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
 8         // pre = cur;
 9         // cur = temp;
10         return reverse(cur,temp);
11     }
12     ListNode* reverseList(ListNode* head) {
13         // 和双指针法初始化是一样的逻辑
14         // ListNode* cur = head;
15         // ListNode* pre = NULL;
16         return reverse(NULL, head);
17     }
18 
19 };
复制代码

 

递归法2:

我们可以发现,上面的递归写法和双指针法实质上都是从前往后翻转指针指向,其实还有另外一种与双指针法不同思路的递归写法:从后往前翻转指针指向。

复制代码
 1 class Solution {
 2 public:
 3     ListNode* reverseList(ListNode* head) {
 4         // 边缘条件判断
 5         if(head == NULL) return NULL;
 6         if (head->next == NULL) return head;
 7         
 8         // 递归调用,翻转第二个节点开始往后的链表
 9         ListNode *last = reverseList(head->next);
10         // 翻转头节点与第二个节点的指向
11         head->next->next = head;
12         // 此时的 head 节点为尾节点,next 需要指向 NULL
13         head->next = NULL;
14         return last;
15     }
16 }; 
复制代码

 

 

 

 

下面给出Java版本分别采用这三种方法的代码:

复制代码
 1 // 双指针
 2 class Solution {
 3     public ListNode reverseList(ListNode head) {
 4         ListNode prev = null;
 5         ListNode cur = head;
 6         ListNode temp = null;
 7         while (cur != null) {
 8             temp = cur.next;// 保存下一个节点
 9             cur.next = prev;
10             prev = cur;
11             cur = temp;
12         }
13         return prev;
14     }
15 }
复制代码
复制代码
 1 // 递归 
 2 class Solution {
 3     public ListNode reverseList(ListNode head) {
 4         return reverse(null, head);
 5     }
 6 
 7     private ListNode reverse(ListNode prev, ListNode cur) {
 8         if (cur == null) {
 9             return prev;
10         }
11         ListNode temp = null;
12         temp = cur.next;// 先保存下一个节点
13         cur.next = prev;// 反转
14         // 更新prev、cur位置
15         // prev = cur;
16         // cur = temp;
17         return reverse(cur, temp);
18     }
19 }
复制代码
复制代码
 1 // 从后向前递归
 2 class Solution {
 3     ListNode reverseList(ListNode head) {
 4         // 边缘条件判断
 5         if(head == null) return null;
 6         if (head.next == null) return head;
 7         
 8         // 递归调用,翻转第二个节点开始往后的链表
 9         ListNode last = reverseList(head.next);
10         // 翻转头节点与第二个节点的指向
11         head.next.next = head;
12         // 此时的 head 节点为尾节点,next 需要指向 NULL
13         head.next = null;
14         return last;
15     } 
16 }
复制代码

 

posted @   Ricentch  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示