利用递归的方式反转一个单向链表
来自leetcode206 难度为简单
这道题有两个方式去反转单向链表,一个为迭代,一个为递归
下面这个是递归的方法
struct ListNode* reverseList(struct ListNode* head) {
if (head==NULL||head->next==NULL) {
return head;
}
struct ListNode* Last = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return Last;
}
如何去理解递归呢
首先当我们想用递归的方法去解决一个问题的时候我们要看这个问题是不是能够
- 拆解成子问题
- 子问题的求解方式和大问题一样
- 存在最小子问题
【反转head指向的带有n个结点的单向链表】就可以拆解【成一个结点接上head.next指向的带有n-1个结点的单向链表】。
当只有一个结点的时候,直接返回那个结点的地址,并用一个Last指针去接收,在归的过程中,不断逆转链表并返回逆转后的头节点。
递归真玄妙啊
下面说下迭代的方法
迭代的方式写需要用到三个指针,pre,cur和next。
用pre和cur去改变链表的指向,用next去保存cur以前指向的地址防止找不到未被逆转的链表
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* pre = NULL;
struct ListNode* cur = head;
struct ListNode* next;
while (cur != NULL)
{
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
下面补充一下如何逆转链表前N个元素
理解了前面的递归过程,也不难理解这个。
区别在于要把未被逆转的结点的地址记住,再让逆转之后的最后一个结点接上未被逆转的结点,以前head->next直接是NULL,现在需要接上未被逆转的链表
//反转链表前n个结点
ListNode seccessor;//递归函数里面不可能会创建新的变量
ListNode reverseN(ListNode head, int n)
{
if (n == 1)
{
successor = head->next;
return head;
}
ListNode Last = reverseN(head->next, n - 1);
head->next->next = head;
head->next = seccessor;
return Last;
}
最后再补充一个从m(位序为m)到n位元素如何逆转
ListNode reverseBetween(ListNode head, int m, int n) {
// base case
if (m == 1) {
return reverseN(head, n);
}
// 前进到反转的起点触发 base case
head.next = reverseBetween(head.next, m - 1, n - 1);
return head;
}