92. 反转链表 II Golang实现

题目描述:

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

思路分析:

没到指定的位置范围时,直接进行链表的链接,然后到了需要转换的范围就将这些节点用一个栈保存,然后再利用栈的先入后出进行节点的链接,最后将剩下的节点进行链接即可。注意代码的逻辑,如果在一个for中进行所有操作可能导致逻辑的混乱,所以最好将各个功能分开实现。用不同的for实现即可,题目给定的left和right可以成为一个分界值,可以之间利用。 但是这样做会利用额外的空间,空间复杂度较高,所以还有一种原地交换的方法。[头插法]
点击查看代码

func reverseBetween(head *ListNode, left int, right int) *ListNode {
    if head == nil || left == right {
        return head
    }

    // 创建 dummy 节点来处理边界情况
    dummy := &ListNode{Next: head}
    pre := dummy

    // 1. 定位到 `left` 前一个节点
    for i := 1; i < left; i++ {
        pre = pre.Next
    }

    // 2. 使用栈保存 `left` 到 `right` 范围的节点
    var stack []*ListNode
    cur := pre.Next
    for i := left; i <= right; i++ {
        stack = append(stack, cur)
        cur = cur.Next
    }

    // 3. 出栈并反转连接节点
    for len(stack) > 0 {
        pre.Next = stack[len(stack)-1] // 连接出栈的节点
        stack = stack[:len(stack)-1]   // 出栈
        pre = pre.Next                 // 移动 pre 指针
    }

    // 4. 连接剩余的部分
    pre.Next = cur

    return dummy.Next
}

头插法原地交换

找到第一个需要反转的结点的前一个结点 p,从这个结点开始,依次把后面的结点用"头插"法,插入到 p 结点的后面。循环次数用 n-m 来控制。 重点查看最后一个for循环实现的头插法的代码。
点击查看代码

func reverseBetween(head *ListNode, left int, right int) *ListNode {
    if head == nil || left == right {
        return head
    }

    // 创建 dummy 节点,帮助处理头节点的边界情况
    dummy := &ListNode{Next: head}
    pre := dummy

    // 将 pre 移动到 left 前一个节点的位置
    for i := 1; i < left; i++ {
        pre = pre.Next
    }

    // 开始反转的位置
    cur := pre.Next
    var next *ListNode

    // 反转指定区域的节点
    for i := 0; i < right-left; i++ {
        next = cur.Next
        cur.Next = next.Next
        next.Next = pre.Next
        pre.Next = next
    }

    return dummy.Next
}