链表问题1——递归反转链表

链表问题1——递归反转链表

一.前言

之前系统的把二叉树的大部分问题都过了一遍,但是目前还没有系统的总结,过两天要再梳理一下,整一篇汇总博客,自己理理思路。现在开始链表问题的复习。

反转单链表的迭代实现不是一个困难的事情,但是递归实现就有点难度了。再难一点,如果只反转单链表中的一部分,是否能够递归实现。

public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

迭代的思路:先用一个for循环找到第m个位置,再用一个for循环将m和n之间的元素反转。

迭代思路简单,但是细节问题很多;递归就要简洁很多。

二.递归反转整个链表

下面这个算法很经典,常用来显示递归的巧妙和优美。

ListNode reverse(ListNode head){
	if(head.next==null) return head;
	ListNode last = reverse(head.next);
	head.next.next=head;
	head.next = null;
	return last;
}

再强调一次:递归算法最重要的就是明确递归函数的定义,具体到reverse函数:输入一个节点head,将以head为起点的链表反转,并返回反转之后的头结点。

我们不去深究具体的递归细节,下面这个代码,反正实现的就是把以head.next为起点的链表反转,并返回反转之后的头结点last。

ListNode last = reverse(head.next);

在这里插入图片描述

在这里插入图片描述
head.next指向的是2,将2.next再指向head,将原本的head变为尾部了。

head.next.next=head;

在这里插入图片描述
最后:

head.next =null;
return last;

在这里插入图片描述
至此,整个链表就反转过来了,在这里还有两个地方要注意:

  1. 递归算法,都要有一个base case,在这里就是:if(head.next==null) return head;
  2. 还要重新将尾指针指向null。

三.反转链表前N个节点

// 将链表的前 n 个节点反转(n <= 链表长度)
ListNode reverseN(ListNode head, int n)

如:执行 reverseN(head,3)

在这里插入图片描述

ListNode successor = null; //后驱节点
//反转以head为起点的n个节点,返回新的头节点
ListNode reverseN(ListNode head,int n){
	if(n==1){
	//记录第n+1个节点,base case
	successor = head.next;
	return head;
	}
	//以head.next为起点,需要反转前n-1个节点
	ListNode last = reverseN(head.next,n-1);
	head.next.next=head;
	head.next = successor;
	return last;
}

和反转整个链表的区别:

  1. base case变为n=1,反转一个元素,就是自己本身,同时要记录后驱节点
  2. 反转整个链表直接将head.next=null;但是这里我们不知道head。next后面还有没有链表节点,所以要提前记录原本的下一节点successor,然后最后将其赋值给head.next。

在这里插入图片描述

四.反转链表的一部分

给一个索引区间[m,n](索引从 1 开始),仅仅反转区间中的链表元素。

ListNode reverseBetween(ListNode head, int m, int n)

如果m=1,就跟刚才的reverseN的情况一样,那如果m!=1,假设head.next的索引就是1,那么对应的head.next应该表示为从第m-1个元素开始的。。。依次递归:

ListNode reverseBetween(ListNode head, int m, int n){
	if(m==1)
		return reversN(head,n);
	//前进到反转的起点触发base case
	head.next = reverseBetween(head.next,m-1,n-1);
	return head;
}

值得一提的是,递归操作链表并不高效。和迭代解法相比,虽然时间复杂度都是 O(N),但是迭代解法的空间复杂度是 O(1),而递归解法需要堆栈,空间复杂度是 O(N)。所以递归操作链表可以作为对递归算法的练习,但是考虑效率的话还是使用迭代算法更好。

迭代解法:

在这里插入代码片
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值