反转链表

137 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

反转链表

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

未命名文件.png

数据反转,最容易想到的是使用栈,因为栈天然的先进后出的特性可以很方便实现反转,我们只需要按顺序将链表中的节点依次入栈,然后出栈并组成新的链表就可以了,代码如下:

fun reverseList(head: ListNode?): ListNode? {
    val temp = Stack<ListNode>()
    var currNode = head
    //将节点全部放到栈中
    while (currNode != null) {
        temp.push(currNode)
        currNode = currNode.next
    }
    if (temp.isEmpty()) {
        return null
    }
    //取出节点,重新组成新的链表
    val newHead = temp.pop()
    var last = newHead
    while (temp.isNotEmpty()) {
        val top = temp.pop()
        last.next = top
        last = top
    }
    last.next = null
    return newHead
}

需要注意的是最后一步last.next = null不能省略,因为最后一个出栈的节点是原链表的头结点,需要把其next指向null否则构成环。

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(n)。因为使用了栈暂存链表中的节点。

双指针

反转链表的时候,如果我们能在纸上先画出过程,就很容易想到双指针的方法,无非就是把原来的指向关系反转一下,代码如下:

fun reverseList(head: ListNode?): ListNode? {
    var preNode:ListNode?=null
    var currentNode = head
    while (currentNode!=null){
        val next = currentNode.next
        currentNode.next = preNode
        preNode = currentNode
        currentNode = next
    }
    return preNode
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。需要遍历链表一次。
  • 空间复杂度:O(1)。

递归

我们在反转的时候,遇到一个节点,假设链表其余节点已经完成反转,则我们只需要反转它前面的部分,代码如下:

fun reverseList(head: ListNode?): ListNode? {
    if (head?.next == null) {
        return head
    }
    val temp = reverseList(head.next);
    head.next?.next = head
    head.next = null
    return temp
}

需要注意的是在递归的过程中必须吧当前节点的next指向null,也就是代码中的head.next = null,不然就会出现环。

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)