LeetCode 75. 颜色分类 - 双指针法高效解决(Java实现)

文章目录

本文介绍一种时间复杂度O(n)、空间复杂度O(1)的优雅解法,通过双指针技术实现颜色分类的一趟扫描排序

问题描述

给定一个包含红色(0)、白色(1)和蓝色(2)的数组 nums,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色的顺序排列。

示例:

java 复制代码
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

算法思路:三指针分区法

核心思想

使用三个指针将数组分为四个区域:

  1. [0, p0):已排序的0区域
  2. [p0, curr):已排序的1区域
  3. [curr, p2]:待处理区域
  4. (p2, end]:已排序的2区域

指针定义

  • p0:指向下一个0应放置的位置(0区域的右边界)
  • p2:指向下一个2应放置的位置(2区域的左边界)
  • curr:当前遍历指针,负责处理元素交换

Java实现

java 复制代码
class Solution {
    public void sortColors(int[] nums) {
        if (nums == null || nums.length < 2) return;
        
        int p0 = 0;                   // 0区域右边界
        int p2 = nums.length - 1;     // 2区域左边界
        int curr = 0;                 // 当前遍历指针
        
        while (curr <= p2) {
            switch (nums[curr]) {
                case 0:
                    // 将0交换到0区域
                    swap(nums, curr++, p0++);
                    break;
                case 1:
                    // 1保留在中间区域
                    curr++;
                    break;
                case 2:
                    // 将2交换到2区域
                    swap(nums, curr, p2--);
                    // 注意:curr不自增,需检查交换来的新元素
                    break;
            }
        }
    }
    
    // 辅助交换函数
    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

算法执行流程

  1. 初始化指针

    • p0 = 0(0区域起始位置)
    • p2 = nums.length-1(2区域起始位置)
    • curr = 0(从数组开头遍历)
  2. 元素处理逻辑

    • 遇到0 :与p0交换,p0curr右移
    • 遇到1 :跳过,curr右移
    • 遇到2 :与p2交换,p2左移(curr不变)
  3. 终止条件curr > p2(所有元素处理完毕)

关键问题解析:为什么交换0后不需要重新检查?

交换0时的两种情况分析

情况 条件 交换前状态 交换后状态
情况1 curr > p0 nums[p0] = 1 nums[curr] = 1
情况2 curr == p0 自身交换 保持不变

详细解释:

  1. curr > p0

    • p0位置必定是1(因为0区域和1区域已排序)
    • 交换后curr位置变为1 → 可直接跳过处理(1属于中间区域)
  2. curr == p0

    • 自身交换无实际变化
    • 元素保持0 → 属于已排序区域

结论 :交换0后curr位置的新元素只可能是0或1,都无需再次处理,因此可以直接移动curr指针。

复杂度分析

指标 说明
时间复杂度 O(n) 单次遍历完成排序
空间复杂度 O(1) 仅使用常数级额外空间

示例演示(输入:[2,0,2,1,1,0])

步骤 操作 数组状态 指针变化
1 初始状态 [2,0,2,1,1,0] p0=0, p2=5, curr=0
2 处理2:交换curr↔p2 [0,0,2,1,1,2] p2=4
3 处理0:交换curr↔p0 [0,0,2,1,1,2] p0=1, curr=1
4 处理0:交换curr↔p0 [0,0,2,1,1,2] p0=2, curr=2
5 处理2:交换curr↔p2 [0,0,1,1,2,2] p2=3
6 处理1:跳过 [0,0,1,1,2,2] curr=3
7 处理1:跳过 [0,0,1,1,2,2] curr=4 > p2(结束)

总结

双指针法解决颜色分类问题的核心在于:

  1. 通过p0p2维护已排序区域
  2. curr指针动态处理待排序区域
  3. 巧妙利用交换操作实现元素归位
  4. 利用数组分区特性优化操作步骤(交换0后无需重检)

该算法是荷兰国旗问题的经典解法,体现了双指针技术在数组原地操作中的高效性,是面试中的高频考点。

相关推荐
小指纹1 小时前
2025山东CCPC题解
c++·算法
guitarjoy2 小时前
Compose原理 - 整体架构与主流程
java·开发语言
babicu1232 小时前
CSS Day07
java·前端·css
小鸡脚来咯3 小时前
spring IOC控制反转
java·后端·spring
怡人蝶梦4 小时前
Java后端技术栈问题排查实战:Spring Boot启动慢、Redis缓存击穿与Kafka消费堆积
java·jvm·redis·kafka·springboot·prometheus
瓯雅爱分享5 小时前
MES管理系统:Java+Vue,含源码与文档,实现生产过程实时监控、调度与优化,提升制造企业效能
java·mysql·vue·软件工程·源代码管理
PixelMind5 小时前
【LUT技术专题】图像自适应3DLUT
图像处理·深度学习·算法·3dlut
鬼多不菜5 小时前
一篇学习CSS的笔记
java·前端·css
深色風信子5 小时前
Eclipse 插件开发 5.3 编辑器 监听输入
java·eclipse·编辑器·编辑器 监听输入·插件 监听输入