面试经典150题[066]:分隔链表(LeetCode 86)

分隔链表(LeetCode 86)

题目链接:分隔链表(LeetCode 86)

难度:中等

1. 题目描述

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。

示例:

复制代码
输入: head = [1,4,3,2,5,2], x = 3
输出: [1,2,2,4,3,5]

输入: head = [2,1], x = 2
输出: [1,2]

2. 问题分析

2.1 规律

  • 这是一个链表的划分问题,需要将节点根据其值与 x 的关系分成两部分。
  • 关键要求是保持每个分区内部节点的 原始相对顺序。这意味着我们不能简单地通过交换节点值来解决,而需要移动节点。

2.2 双链表(双指针)思路

最直观且高效的方法是创建两个新的链表,一个用来存放所有小于 x 的节点,另一个用来存放所有大于或等于 x 的节点。

  • 创建哑节点(Dummy Nodes):

    • less_head:作为 "小于 x" 链表的头节点。
    • greater_head:作为 "大于等于 x" 链表的头节点。
    • 使用哑节点可以简化边界条件的处理,避免对头节点的特殊判断。
  • 创建遍历指针:

    • less_ptr:指向 "小于 x" 链表的尾部。
    • greater_ptr:指向 "大于等于 x" 链表的尾部。
  • 遍历原链表:

    • 用一个指针 current 遍历原链表 head。
    • 对于每个节点 current:
      • 如果 current.val < x,则将其链接到 less_ptr 的后面,并移动 less_ptr。
      • 如果 current.val >= x,则将其链接到 greater_ptr 的后面,并移动 greater_ptr。
  • 拼接链表:

    • 遍历结束后,我们得到了两个独立的链表。
    • 将 "小于" 链表的尾部 (less_ptr) 指向 "大于等于" 链表的头部 (greater_head.next)。
    • 重要 :将 "大于等于" 链表的尾部 (greater_ptr) 的 next 指针设为 None,以防止产生环。
    • 返回 less_head.next作为新链表的头节点。

3. 代码实现

Python

python 复制代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

class Solution:
    def partition(self, head: ListNode, x: int) -> ListNode:
        # 创建两个哑节点,分别作为两个新链表的头
        less_head = ListNode(-1)
        greater_head = ListNode(-1)
        
        # 创建两个指针,用于构建新链表
        less_ptr = less_head
        greater_ptr = greater_head
        
        current = head
        while current:
            if current.val < x:
                # 将节点加入到 'less' 链表
                less_ptr.next = current
                less_ptr = less_ptr.next
            else:
                # 将节点加入到 'greater' 链表
                greater_ptr.next = current
                greater_ptr = greater_ptr.next
            
            # 移动到下一个节点
            current = current.next
        
        # 将 'greater' 链表的末尾指向 None,断开与原链表的连接
        greater_ptr.next = None
        
        # 将 'less' 链表的末尾连接到 'greater' 链表的头部
        less_ptr.next = greater_head.next
        
        return less_head.next

C++

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        // 创建哑节点
        ListNode* less_head = new ListNode(-1);
        ListNode* greater_head = new ListNode(-1);
        
        // 创建构建指针
        ListNode* less_ptr = less_head;
        ListNode* greater_ptr = greater_head;
        
        ListNode* current = head;
        while (current != nullptr) {
            if (current->val < x) {
                less_ptr->next = current;
                less_ptr = less_ptr->next;
            } else {
                greater_ptr->next = current;
                greater_ptr = greater_ptr->next;
            }
            current = current->next;
        }
        
        // 断开 'greater' 链表的尾部
        greater_ptr->next = nullptr;
        
        // 拼接两个链表
        less_ptr->next = greater_head->next;
        
        // 释放哑节点内存(可选,但好习惯)
        ListNode* new_head = less_head->next;
        delete less_head;
        delete greater_head;
        
        return new_head;
    }
};

4. 复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的节点数。我们只需要遍历一次原链表。
  • 空间复杂度 :O(1),我们只使用了常数个额外指针(less_head, greater_head, less_ptr, greater_ptr),并没有创建新的节点,只是重新组织了原链表的节点。

5. 总结

  • 链表划分 问题,特别是要求保持相对顺序时,双链表(或双指针+哑节点) 方法是一个非常经典且有效的解决方案。
  • 使用哑节点可以极大地简化代码逻辑,避免对头节点的空指针判断和特殊处理。
  • 最后一定要记得处理好两个链表的拼接以及新链表尾部的 next 指针(设置为 None/nullptr)。

复习

面试经典150题006:旋转数组(LeetCode 189)

面试经典150题036:旋转图像(LeetCode 48)

面试经典150题051:用最少数量的箭引爆气球(LeetCode 452)

相关推荐
frjc2 小时前
分布式服务拆分实战指南:从底层逻辑到面试话术
微服务·面试·职场和发展
考研保研资料分享2 小时前
2025生科保研北大直博:英语摘要、科研PPT与赶场复盘
面试
香蕉大香蕉(06敬畏市场)3 小时前
MySQL 单点详解(01)
java·数据库·mysql·面试·博客·实习
ShineWinsu3 小时前
对于Qt:QCheckBox常见属性的详细解析
c++·qt·面试·笔试·gui·qcheckbox·多选框
师夷长技以自愈3 小时前
第 3 讲:多 Agent——Supervisor 分诊 + 专职 Worker
面试
怕浪猫4 小时前
我有个朋友,工作八年,公司从 300 人减到 80 人
面试·程序员
考研保研资料分享4 小时前
2024财会跨保北大金融科技:三场笔面试与经管法混申复盘
科技·面试·金融
旖旎夜光4 小时前
LeetCode 315: 算右侧小于当前元素的个数(归并排序) —— 题解
c++·学习·算法·leetcode·排序算法
文丑颜不良啊4 小时前
LeetCode1401~1420题目解析
java·leetcode
Nuanyt4 小时前
LeetCode Hot 100 链表专题2 3 题 (Java)
java·笔记·算法·leetcode·链表