LogicStack-LeetCode 题解:769. 最多能完成排序的块 —— 循环不变量驱动的 O(n) 模拟

发布时间:2026/10/10 8:58:45
LogicStack-LeetCode 题解:769. 最多能完成排序的块 —— 循环不变量驱动的 O(n) 模拟
教程文档【免费下载链接】LogicStack-LeetCode公众号「宫水三叶的刷题日记」刷穿 LeetCode 系列文章源码项目地址https://gitcode.com/gh_mirrors/lo/LogicStack-LeetCode点击查看免费下载本篇技术指南以「宫水三叶的刷题日记」刷穿 LeetCode 系列仓库LogicStack-LeetCode中的 769. 最多能完成排序的块中等 题解为骨架完整还原题目约束、模拟解法与四语言实现并结合仓库内同主题的 768. 最多能完成排序的块 II 与 915. 分割数组 进行横向对比。读完本文你将掌握「利用排列特性设计循环不变量、单趟扫描完成数组分块计数」这一经典模拟范式并能在 Java / C / Python / TypeScript 中直接复用对应实现。一、题目回顾排列数组的分块排序问题给定一个长度为n的整数数组arr它表示[0, n - 1]范围内整数的排列即每个元素各不相同且恰好覆盖0到n - 1的全部整数。操作要求如下将arr分割成若干块分区对每个块单独排序将所有块排序后的结果连接起来使得连接结果与「对原数组整体按升序排序」后的数组完全相同。返回数组能分成的最多块数量。示例分析示例 1输入: arr [4,3,2,1,0] 输出: 1解释将数组分成 2 块或更多块都无法得到所需结果。例如分成[4, 3], [2, 1, 0]连接结果是[3, 4, 0, 1, 2]并非有序数组。示例 2输入: arr [1,0,2,3,4] 输出: 4解释可以分成两块例如[1, 0], [2, 3, 4]但分成[1, 0], [2], [3], [4]可以得到最多块数 4。数据约束约束项取值数组长度n arr.length1 n 10元素取值0 arr[i] n元素互异性arr中每个元素都不同由于arr是[0, n - 1]的排列元素值与下标之间存在天然的对应关系——这正是本题可以采用单趟模拟的根本前提。值得注意的是本题是 LeetCode 上 Tag 为「模拟」的题目在仓库的 Index/模拟.md 索引中可找到同类的模拟题全集。二、核心思路设计一组「循环不变量」本题考察的是简单模拟能力或者说是对「循环不变量」的设计能力。从前往后处理所有arr[i]并维护以下四个变量使它们在任意时刻都精确描述「当前正在考察的未封闭块」的状态变量语义初始值i当前划分块的右边界下标0随循环推进j当前划分块的左边界下标0min当前划分块中元素的最小值arr[0]或nmax当前划分块中元素的最大值arr[0]或-1每扫描到一个元素立即更新块内的min与maxmin min(min, arr[i]) max max(max, arr[i])封闭块的判定条件当且仅当j min且i max时下标范围[j, i]排序后的结果恰好为[min, max]此时可以封闭当前块。判定成立后执行ans // 块数量加一 j i 1 // 下一块的左边界 min n // 重置最小值 max -1 // 重置最大值然后继续循环统计下一个块的信息。为什么这个判定是充分的可以从两个方向理解必要性若[j, i]区间内的元素在排序后恰好填满[min, max]且与最终有序数组的对应位置一致那么该区间的最小值min必须正好等于左边界下标j因为最终有序数组的第j位元素就是j最大值max必须正好等于右边界下标i。否则该块内部排序后无法对齐整体有序数组的相应区间。充分性由于arr是[0, n-1]的排列元素互不重复若当前块的最小值恰为j、最大值恰为i则该块恰好包含j到i共i - j 1个连续整数内部排序后即为[j, j1, ..., i]与整体有序数组的对应区间完全一致。此时封闭该块不会破坏后续分块的可行性。这正是「循环不变量」的典型运用通过维护一组在循环过程中始终成立的变量关系在扫描到满足条件的位置时立即做出最优决策——能切分就切分从而保证块数最多。三、四语言实现可直接运行原题解在仓库 769. 最多能完成排序的块中等 中给出了 Java、C、Python、TypeScript 四种语言的完整实现以下代码与仓库保持一致Javaclass Solution { public int maxChunksToSorted(int[] arr) { int n arr.length, ans 0; for (int i 0, j 0, min n, max -1; i n; i) { min Math.min(min, arr[i]); max Math.max(max, arr[i]); if (j min i max) { ans; j i 1; min n; max -1; } } return ans; } }Cclass Solution { public: int maxChunksToSorted(vectorint arr) { int n arr.size(), ans 0; int j 0, minv n, maxv -1; for (int i 0; i n; i) { minv min(minv, arr[i]); maxv max(maxv, arr[i]); if (j minv i maxv) { ans; j i 1; minv n; maxv -1; } } return ans; } };Pythonclass Solution: def maxChunksToSorted(self, arr: List[int]) - int: n, ans len(arr), 0 j, minv, maxv 0, n, -1 for i in range(n): minv, maxv min(minv, arr[i]), max(maxv, arr[i]) if j minv and i maxv: ans, j, minv, maxv ans 1, i 1, n, -1 return ansTypeScriptfunction maxChunksToSorted(arr: number[]): number { let n arr.length, ans 0 for (let i 0, j 0, min n, max -1; i n; i) { min Math.min(min, arr[i]) max Math.max(max, arr[i]) if (j min i max) { ans; j i 1; min n; max -1; } } return ans }实现要点说明min n、max -1的初值选择由于元素取值域为[0, n-1]用n作为正无穷、-1作为负无穷是安全的哨兵值保证第一个元素进入时能正确初始化块内极值封闭后立即重置j i 1、min n、max -1使循环不变量在新的块上继续成立这是整个算法保持 O(n) 单趟扫描的关键哨兵j min i max四个变量两两配对比较无需额外数组或哈希结构空间开销为零。复杂度时间复杂度O(n)单趟线性扫描空间复杂度O(1)仅使用常数个变量。四、模拟思想在仓库同类题目中的延伸「最多能完成排序的块」是一个经典的分块排序问题家族本仓库中收录了其兄弟题目与相关变体适合对照阅读以建立完整的知识图谱。1. 768. 最多能完成排序的块 II困难允许重复元素最多能完成排序的块 II困难 与本题共享题意但去掉了两条关键限制元素可以重复且输入规模放大到n 2000、元素值域放大到[0, 10^8]。由于元素不再互异、值域也不再与下标一一对应本题的j min i max判定不再适用原题解改用「贪心 构造」将原数组复制并升序排序得到目标序列clone从前往后同步扫描arr与clone用哈希表维护词频差处理arr[i]时计数加一处理clone[i]时计数减一同时维护计数不为 0 的数值数量tot当tot 0时说明arr与clone在前缀区间内的元素构成完全相同仅顺序不同该区间可独立排序块数加一。该解法的时间复杂度为 O(n log n)排序主导空间复杂度 O(n)。两题的对比恰好体现了「排列」与「多重集合」两类输入下同一目标的不同解法路径依赖下标-值对应关系的 O(n) 特解vs通用化的词频比较解法。2. 915. 分割数组中等求唯一分割点分割数组中等 同样是 Tag「模拟」的数组分块题但目标不同要求将数组划分为left和right两个连续子数组使left中每个元素都小于等于right中每个元素且left长度尽可能小返回left的长度。其解法思路与本题同源先一次从后往前遍历统计后缀最小值数组min[i]含义为下标[i, n-1]范围内的最小值再一次从前往后遍历用单变量维护前缀最大值找到第一个满足前缀最大值 后缀最小值的分割点。该解法时间复杂度 O(n)、空间复杂度 O(n)。可以这样理解三者的递进关系题目难度输入特征判定核心复杂度769. 最多能完成排序的块中等[0, n-1]排列元素互异块内min j且max iO(n) 时间 / O(1) 空间768. 最多能完成排序的块 II困难元素可重复值域大与目标序列的词频差tot 0O(n log n) 时间 / O(n) 空间915. 分割数组中等任意数组保证存在划分前缀最大值 后缀最小值O(n) 时间 / O(n) 空间这三篇题解分别收录于 Index/模拟.md 与 Index/贪心算法.md 索引中可以按 Tag 快速检索同类题目。五、总结「769. 最多能完成排序的块」是一道以「模拟」为 Tag 的中等题其价值在于循环不变量的设计示范通过j、i、min、max四个变量维护当前块的完整状态并在状态满足j min i max时立即封闭块从而在 O(n) 时间、O(1) 空间内得到最大分块数对排列特性的精确利用元素与下标的一一对应关系是判定成立的数学根基去掉该特性后问题即刻升级为 768 题的困难版本需要词频比较等更通用的手段与仓库题解体系的衔接本文全部内容以仓库 LeetCode/761-770/769. 最多能完成排序的块中等.md 为基础展开读者可直接在该文件中获取原始题解并在 Index/模拟.md、Index/贪心算法.md 中找到更多同类题目进行系统练习。赞分享教程文档【免费下载链接】LogicStack-LeetCode公众号「宫水三叶的刷题日记」刷穿 LeetCode 系列文章源码项目地址https://gitcode.com/gh_mirrors/lo/LogicStack-LeetCode点击查看免费下载相关推荐LogicStack-LeetCode 题解768. 最多能完成排序的块 II —— 贪心对齐排序后数组与哈希词频匹配的 O(n log n) 解法LogicStack LeetCode 题解768. 最多能完成排序的块 II —— 贪心对齐排序后数组与哈希词频匹配的 O n log n 解法 本篇技术指教程文档LogicStack-LeetCode 题解495. 提莫攻击简单——哨兵变量驱动的 O(n) 区间合并模拟LogicStack LeetCode 题解495. 提莫攻击简单——哨兵变量驱动的 O n 区间合并模拟 本篇以 LogicStack LeetCode教程文档LeetCode 324. 摆动排序 II快选 三数排序的 O(n) 构造详解LogicStack-LeetCode 题解LeetCode 324. 摆动排序 II快选 三数排序的 O n 构造详解LogicStack LeetCode 题解 本篇是「宫水三叶的刷题日记」教程文档上一篇3步装好Zotero中文元数据抓取插件从文件名到完整条目下一篇GetQzonehistory 使用指南快速导出QQ空间全部历史说说创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考