【LeetCode】86. 分隔链表

leetcode

 

解题思路

本问题要求将链表按给定值 x 分割为两部分,所有小于 x 的节点必须出现在大于或等于 x 的节点之前,且需保留原始相对顺序。核心思路是通过 ​​双链表合并法​​ 实现:

  1. ​​构建两个子链表​​:分别存储小于 x 和大于等于 x 的节点。
  2. ​​遍历原链表​​:根据节点值与 x 的关系,将节点追加到对应子链表。
  3. ​​合并链表​​:将小于 x 的子链表尾部连接到大于等于 x 的子链表头部,并断开可能的循环引用。

关键步骤

  1. ​​虚拟头节点​​:简化链表操作,避免处理头节点为空的边界情况。
  2. ​​双指针维护​​:lessTail 和 greaterTail 分别跟踪两个子链表的尾部,实现 O(1) 时间复杂度的追加操作。
  3. ​​循环遍历​​:遍历原链表,根据值大小分配节点到子链表,保持相对顺序。
  4. ​​尾部处理​​:合并前需将 greaterTail.Next 置空,防止原链表中残留指针引发循环。

复杂度分析

  • ​​时间复杂度​​:O(n),仅需一次线性遍历链表。
  • ​​空间复杂度​​:O(1),仅使用固定数量的指针变量。

实现代码

type ListNode struct {
    Val  int
    Next *ListNode
}

func partition(head *ListNode, x int) *ListNode {
    // 创建两个虚拟头节点,用于分别构建小于x和大于等于x的链表
    lessHead := &ListNode{}
    greaterHead := &ListNode{}
    lessTail := lessHead       // 跟踪小于x链表的尾部
    greaterTail := greaterHead // 跟踪大于等于x链表的尾部

    // 遍历原链表,分配节点到对应子链表
    for head != nil {
        if head.Val < x {
            lessTail.Next = head
            lessTail = lessTail.Next
        } else {
            greaterTail.Next = head
            greaterTail = greaterTail.Next
        }
        head = head.Next // 移动到下一个节点
    }

    // 处理大于等于链表的尾部,断开可能的循环引用
    greaterTail.Next = nil

    // 合并两个链表
    lessTail.Next = greaterHead.Next

    // 返回合并后的头节点
    return lessHead.Next
}

代码注释说明

  1. ​​虚拟头节点​​:lessHead 和 greaterHead 作为哨兵节点,简化链表操作。
  2. ​​尾部指针维护​​:通过 lessTail 和 greaterTail 动态更新子链表的尾部,确保追加操作高效。
  3. ​​循环遍历​​:将每个节点按值分配到对应的子链表,保持原链表中的相对顺序。
  4. ​​合并与断开循环​​:合并前需将 greaterTail.Next 置空,避免原链表残留指针导致错误循环。

运行示例

// 辅助函数: 打印链表
func printList(head *ListNode) {
    for head != nil {
        fmt.Printf("%d->", head.Val)
        head = head.Next
    }
    fmt.Println("nil")
}

func main() {
    // 构建输入链表:1 -> 4 -> 3 -> 2 -> 5 -> 2
    l1 := &ListNode{Val: 1}
    l1.Next = &ListNode{Val: 4}
    l1.Next.Next = &ListNode{Val: 3}
    l1.Next.Next.Next = &ListNode{Val: 2}
    l1.Next.Next.Next.Next = &ListNode{Val: 5}
    l1.Next.Next.Next.Next.Next = &ListNode{Val: 2}
    printList(partition(l1, 3)) // 输出:1->2->2->4->3->5->nil

    // 输入链表:2 -> 1
    l2 := &ListNode{Val: 2}
    l2.Next = &ListNode{Val: 1}
    printList(partition(l2, 2)) // 输出:1->2->nil
}
posted @ 2025-04-18 12:37  云隙之间  阅读(11)  评论(0)    收藏  举报