题目描述
给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。 数据范围: 0≤n≤10000≤n≤1000
要求:空间复杂度 O(1),时间复杂度 O(n) 。
如当输入链表{1,2,3}时,经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。
以上转换过程如下图所示:
解题思路
题目给定了一个单链表的头结点 pHead
,长度为 n
,要求将该链表反转并返回新链表的表头。我们不妨先考虑使用递归法,先递归到链表的末端,再从末端开始反转链表的指针,递归到头结点时,返回新的头结点,
/**
* class ListNode(var `val`: Int) {
* var next: ListNode? = null
* }
*/
object Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* @param head ListNode类
* @return ListNode类
*/
fun ReverseList(head: ListNode?): ListNode? {
// 递归终止条件:链表为空或只有一个节点
if (head?.next == null) return head
// 递归反转剩余的链表
val newHead = ReverseList(head.next)
// 将当前节点的下一节点的 next 指向当前节点
head.next!!.next = head
head.next = null // 当前节点的 next 置空
return newHead // 返回新的头结点
}
}
但我们很快回意识到由于递归调用栈空间复杂度为 O(n),不符合题目要求,因此不仅递归法不能使用,使用栈方法也不能满足题目要求。
为了满足时间复杂度为 O(n) 和空间复杂度为O(1) 的要求,我们可以通过迭代的方法反转链表。迭代法通过遍历链表并逐一反转节点的指针来实现。
我们定义一个 ListNode
类表示链表的节点,并在 Solution
对象中实现 ReverseList
方法。具体实现如下:
/**
* class ListNode(var `val`: Int) {
* var next: ListNode? = null
* }
*/
object Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* @param head ListNode类
* @return ListNode类
*/
fun ReverseList(head: ListNode?): ListNode? {
var prev: ListNode? = null
var current = head
while (current != null) {
val nextNode = current.next // 暂存下一个节点
current.next = prev // 反转当前节点的指针
prev = current // 移动 prev 到当前节点
current = nextNode // 移动 current 到下一个节点
}
return prev // 返回新的头结点
}
}
根据题目所给的流程图,我们需要定义三个指针 prev
、current
和 nextNode
,其中 prev
用于保存当前节点的前一个节点,current
用于遍历链表,nextNode
用于保存当前节点的下一个节点。对于每个节点:保存当前节点的下一个节点到 nextNode
,将当前节点的 next
指针指向 prev
,将 prev
更新为当前节点,然后将 current
更新为 nextNode
,当 current
为 null
时,迭代结束,此时 prev
为新链表的表头。
相比于递归反转链表,迭代法由于没有递归调用栈的额外空间消耗,更符合空间复杂度为 O(1)的要求。