新闻详情

新闻详情

首页 / 资讯中心 / 详情

Hot 100 --- 颜色分类

发布时间:2026/9/30 7:25:55来源:尧图网络
Hot 100 --- 颜色分类
本文概览本文讲解颜色分类荷兰国旗问题只有 0、1、2 三个值0 要排到最前面、2 要排到最后面中间剩下的自然是 1方法一是统计个数后重写方法二用左右两个指针各守一端一边遍历一边把 0 往左扔、2 往右扔只需一遍扫描一、题目二、题目分析1. 题目要求给定一个包含红色、白色和蓝色、共n个元素的数组nums原地对它们进行排序使得相同颜色的元素相邻并按照红色、白色、蓝色顺序排列。用整数0、1和2分别表示红色、白色和蓝色。必须在不使用库内置的sort函数的情况下解决这个问题。示例 1nums [2, 0, 2, 1, 1, 0]→[0, 0, 1, 1, 2, 2]示例 2nums [2, 0, 1]→[0, 1, 2]2. 怎么想这题题目说得很死数组里只有0、1、2三种值最后要排成所有 0 在前面、所有 1 在中间、所有 2 在后面。最直接的做法是先数再填扫一遍统计出 0、1、2 各有多少个然后照着个数把数组从头到尾重写一遍。思路没问题但要扫两遍数组。还能不能再省注意这里只有三个值而且规矩特别简单0的归宿是最前面2的归宿是最后面1夹在中间——也就是说只要把 0 和 2 都送对了地方剩下的位置自然全是 1压根不用管。那就可以在遍历的过程中边看边归位遇到 0 就往数组头部扔遇到 2 就往数组尾部扔。既然要往两端扔就得有两个指针分别记住头部扔到哪了、尾部扔到哪了。这就是双指针的思路一遍扫描就能排好。3. 需要解决哪几个问题问题一两个指针各自指向哪里、分别代表什么含义问题二遇到 0 或 2 时需要交换交换之后两个指针和遍历下标分别怎么移动问题三最容易错的细节为什么遇到 0 时遍历下标要往后走一格遇到 2 时却要停在原地再看一次三、方法一统计个数后重写两遍遍历1. 思路概览publicvoidsortColors(int[]nums){intcount00,count10,count20;// 第一遍数出各有多少个for(intnum:nums){if(num0)count0;elseif(num1)count1;elsecount2;}// 第二遍按个数把数组重新填满intidx0;for(intk0;kcount0;k)nums[idx]0;for(intk0;kcount1;k)nums[idx]1;for(intk0;kcount2;k)nums[idx]2;}思路简要说明第一遍统计数出 0、1、2 各有多少个第二遍填充按 0、1、2 的个数依次覆盖回数组时间复杂度 O(n)空间 O(1)只用三个计数器缺点要扫两遍数组2. 思路详解这个方法的逻辑和桶排序是一回事既然知道了每种值该占多少格直接按格子填就行了。以[2, 0, 2, 1, 1, 0]为例第一遍数完count0 2, count1 2, count2 2 第二遍填充前 2 格填 0 → [0, 0, _, _, _, _] 接着 2 格填 1 → [0, 0, 1, 1, _, _] 最后 2 格填 2 → [0, 0, 1, 1, 2, 2] ✓简单可靠代价是要遍历两遍。既然一趟就能解决就值得往下想。3. 复杂度分析时间复杂度 O(n)两遍线性扫描。空间复杂度 O(1)三个计数器。四、能不能一遍扫完回顾一下刚才那个观察0 的归宿是数组最左边2 的归宿是最右边而 1 只要站在中间就行。既然两个极端值各有明确的目的地那就可以一边遍历一边送它们回家遇到0把它和当前最左边还没确定的位置交换——这样 0 就落到该去的地方那个位置可以划进0 区了遇到2把它和当前最右边还没确定的位置交换——2 就落到尾部那个位置划进2 区遇到1先别动它让它在原地等着等 0 和 2 都归位它自然就落在中间了。于是需要两个指针一个盯左、一个盯右分别记录0 区和2 区已经推进到哪儿。下面是具体怎么落地。五、方法二双指针三路分区一遍遍历1. 思路概览publicvoidsortColors(int[]nums){intleft0;// 0 区的下一个空位intrightnums.length-1;// 2 区的上一个空位inti0;// 当前考察的位置while(iright){if(nums[i]0){// 把 0 换到左边界inttempnums[i];nums[i]nums[left];nums[left]temp;left;i;}elseif(nums[i]2){// 把 2 换到右边界inttempnums[i];nums[i]nums[right];nums[right]temp;right--;}else{// 是 1留在原地继续往后看i;}}}思路简要说明left[0, left)这一段已经全是 0left指向 0 区的下一个空位right(right, n-1]这一段已经全是 2right指向 2 区的上一个空位i当前正在考察的位置它前面的[left, i)全是 1循环条件i right[i, right]才是还没处理的区间i越过right就说明处理完了时间复杂度 O(n)空间 O(1)2. 思路详解第一步两个指针 一个遍历下标各自管什么把整个数组看成四段[ 0 区 ) [ 1 区 ) [ 待处理区 ] ( 2 区 ] 0 left i right n-1[0, left)已排好的 0全是 0[left, i)已排好的 1[i, right]还没看过的部分(right, n-1]已排好的 2。每处理完一个元素就把它塞进对应的段里待处理区随之缩小。等i right待处理区空了整段数组就排好了。第二步三种情况分别怎么处理情况一nums[i] 0。它该去最前面。把它和nums[left]交换——left那个位置正是 0 区的下一个空位换过去正好落位。然后left0 区往前扩一格、i这一位已经处理完了往后看下一个。情况二nums[i] 2。它该去最后面。把它和nums[right]交换——right是 2 区的上一个空位换过去落位。然后right--2 区往前扩一格。情况三nums[i] 1。1 不用挪让它待在原地即可直接i往后看。等 0 和 2 各自归位这些留在中间的 1 自然就聚成了中间的 1 区。第三步为什么 0 要i2 却不i这是这个方法唯一值得琢磨的地方关键看换过来的那个数是谁。遇到 0 时和nums[left]交换。而left永远落在i的左边left ≤ i它左边那段[0, left)全是 0、[left, i)全是 1——所以nums[left]位置上待着的一定是一个 1当left i时而这个 1 早就被考察过了它属于已排好的 1 区。换过来之后nums[i]变成了 1这个 1 本来就该待在中间不用再管所以i可以直接往后走。遇到 2 时和nums[right]交换。而right永远在i的右边它属于还没考察过的待处理区。也就是说nums[right]可能是 2、可能是 1、也可能是 0——换到nums[i]上的这个新值谁也不知道是什么。所以这一位必须留在原地重新考察一遍此时i不能动。一句话概括0 换过来的是已经看过的 1放心往前走2 换过来的是从没见过的数必须停下再看一眼。第四步完整执行过程以示例 1nums [2, 0, 2, 1, 1, 0]为例。初始left 0, right 5, i 0初始: [2, 0, 2, 1, 1, 0] left0 right5 i0 i0: nums[0]2 → 和 nums[5] 换 → [0, 0, 2, 1, 1, 2] right4 i0 换过来的是 0还得再看i 不动 i0: nums[0]0 → 和 nums[0] 换自己换自己 → [0, 0, 2, 1, 1, 2] left1 i1 i1: nums[1]0 → 和 nums[1] 换自己换自己 → [0, 0, 2, 1, 1, 2] left2 i2 i2: nums[2]2 → 和 nums[4] 换 → [0, 0, 1, 1, 2, 2] right3 i2 换过来的是 1是刚看过的类型但要按未考察处理所以留在原地再看 i2: nums[2]1 → 是 1不挪i3 i3: nums[3]1 → 是 1不挪i4 此时 i4 right3待处理区空了循环结束 结果: [0, 0, 1, 1, 2, 2] ✓再看示例 2nums [2, 0, 1]初始: [2, 0, 1] left0 right2 i0 i0: nums[0]2 → 和 nums[2] 换 → [1, 0, 2] right1 i0 i0: nums[0]1 → 是 1i1 i1: nums[1]0 → 和 nums[0] 换 → [0, 1, 2] left1 i2 此时 i2 right1循环结束 结果: [0, 1, 2] ✓可以看到i0那一步换过来的 1 还没被考察过所以停在原地看了一下才发现它是 1才往后走——这正是2 不i的必要性。3. 复杂度分析时间复杂度 O(n)每个元素最多被处理常数次i一路向右、right一路向左合起来推进 O(n) 步。空间复杂度 O(1)只有三个下标变量原地交换。六、总结方法遍历次数时间空间关键点统计个数后重写两遍O(n)O(1)先数再填简单但要多扫一遍双指针三路分区一遍O(n)O(1)0 往左扔、2 往右扔1 留在中间这题的灵魂在于发现只有三个值而且两个极端值各有明确归宿0 该在最左、2 该在最右所以用左右两个指针各守住一端剩下的 1 不用管它会被自然地夹在中间。真正容易写错的是移动下标的时机遇到 0 交换后i因为换回来的一定是已经看过的 1遇到 2 交换后i不动因为从右边换回来的是一个从没考察过的数必须重新判断。把这一点想通了这个双指针就是标准的荷兰国旗问题解法三路分区只扫一遍、只用常数空间。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

【NLP】大模型长文本处理技术与GLM-4-Plus评测:从上下文窗口到TaoToken统一调用 2026/9/30 13:51:19

【NLP】大模型长文本处理技术与GLM-4-Plus评测:从上下文窗口到TaoToken统一调用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
【Linux指南】动静态库系列(九):动态库如何进入进程地址空间:从磁盘 .so 到共享内存映射 2026/9/30 13:51:06

【Linux指南】动静态库系列(九):动态库如何进入进程地址空间:从磁盘 .so 到共享内存映射

文章目录一、动态库为什么比静态库更常用二、动态库也是文件三、动态库加载的整体流程四、从磁盘 .so 到物理内存五、从物理内存到进程虚拟地址空间六、多个进程如何共享同一个动态库七、共享的是代码,不是什么都共享八、为什么动态库加载地址不固定九、使用 /proc …

阅读更多 →
PSE认证证书有效期多久,产品改款后是否需要重新做认证? 2026/9/30 13:50:59

PSE认证证书有效期多久,产品改款后是否需要重新做认证?

PSE并不是一张所有产品都按统一年限有效的“永久证书”。需要先区分产品是否属于特定电气用品,以及企业持有的是符合性检查证书、检测报告还是其他合规文件。产品改款后,也不能仅凭外观变化判断是否需要重新认证,关键要看改动是否影响安全结构…

阅读更多 →
企业级AI知识库建设实战:从RAG架构到混合检索与元数据治理 2026/9/30 13:50:45

企业级AI知识库建设实战:从RAG架构到混合检索与元数据治理

开头今年上半年,我们海博团队在推进 AI-Native 研发体系的时候,发现一个特别扎心的事实:模型能力早就不是瓶颈了,真正卡住团队进度的是知识底座。代码仓库里那些散落的决策文档、写了没人看的架构说明、只有某个老员工脑子里的业务…

阅读更多 →
渲染书籍目录汇总:六大分支与学习路径全解析 2026/9/30 13:50:45

渲染书籍目录汇总:六大分支与学习路径全解析

作为常年跟渲染打交道的人,我书架上的这份“渲染书籍目录汇总”已经维护了一年多,标题里的“不断更新中”不是客套话,是真实状态。之所以维护这个目录,是因为每年都要被问同一个问题:想学渲染,到底该看哪些…

阅读更多 →
渲染书籍目录汇总:从实时渲染到引擎源码的系统学习路径 2026/9/30 13:50:45

渲染书籍目录汇总:从实时渲染到引擎源码的系统学习路径

做渲染相关工作这些年,陆陆续续收了不下五十本相关的书,真正从头翻到尾的却没几本。这次给自己定了个小目标,按照“实时渲染、离线渲染、引擎源码、工程实践”四个方向,把值得读的书和它们的目录结构重新整理了一遍,顺…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉