ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LeetCode 2808 使循环数组中所有元素相等的最少秒数:扩散模型、环形破环与多语言实现深度解析

LeetCode 2808 使循环数组中所有元素相等的最少秒数:扩散模型、环形破环与多语言实现深度解析 科学计算【免费下载链接】codeforces-go算法竞赛模板库 by 灵茶山艾府 项目地址https://gitcode.com/GitHub_Trending/co/codeforces-go点击查看免费下载导读本文围绕力扣第 110 场双周赛第三题「Minimum Seconds to Equalize a Circular Array使循环数组中所有元素相等的最少秒数」展开以 leetcode/biweekly/110/c/README.md 的官方题解为主体骨架并结合本仓库灵茶山艾府维护的算法竞赛模板库 codeforces-go中与之配套的 Go 实现、测试文件 与 测试数据 进行源码级佐证。读完本文你将掌握「环形数组 同步扩散」类题目的核心建模方法——枚举最终值、按相同值分组、破环成链、取相邻间距的最大值再除二并能直接用 Python / Java / C / Go 四种语言写出线性复杂度的标准解。一、题目回顾与仓库定位题意简述给定一个长度为 $n$ 的 0-index 循环数组nums。每一秒对于每个下标 $i$你可以把nums[i]变为其左右邻居nums[(i-1n)%n]或nums[(i1)%n]也可以保持不变。求使整个数组所有元素相等所需的最少秒数。本题在仓库中的完整资源位于 leetcode/biweekly/110/c/ 目录下文件作用README.md官方题解三个提示 四语言实现 复杂度分析c.goGo 版标准实现c_test.go由模板自动生成的单测文件c.txt3 组官方示例数据输入/输出按行交替存放其中 c_test.go 的注释还给出了本题在力扣上的两道对应链接周赛原题与题库常规题便于读者回链原题进行在线提交。二、核心观察最终值必然来自原数组提示 1题解的第一个提示是最终所有元素一定变成了一个在 $\textit{nums}$ 中的数。枚举这个数。这个结论是整道题的突破口证明很简单每一秒发生的操作只是把某个位置的值复制成它邻居的值。无论操作多少次数组中的值集合始终是初始数组nums中值的子集——不会产生任何新数。因此如果最终整个数组能变成同一个数 $x$那么 $x$ 必然已经出现在初始的nums中。这一步把枚举最终值的问题规模压缩到了 $n$ 个位置而相同值只需要考虑一次。算法于是变成枚举每个可能成为最终值的数 $x$计算仅靠所有等于 $x$ 的位置向外扩散覆盖整个环形数组需要多少秒取所有 $x$ 对应耗时中的最小值。三、扩散模型每秒钟向左右各扩散一位提示 2单源的扩散速度假设某个位置的值等于 $x$那么每一秒它都能让相邻一格变成 $x$。换句话说$x$ 以每秒 1 格的速度向左右两边扩散$t$ 秒后以该位置为中心的一段连续区间含自身共 $2t1$ 个位置都会变成 $x$。多源同时扩散取决于最远相邻对由于数组中可能有多个位置初始值就是 $x$它们同时向外扩散相互配合可以显著缩短耗时。题解提示 2 指出多个相同数字 $x$ 同时扩散那么扩散完整个数组的耗时就取决于相距最远的两个相邻的 $x$。设这两个 $x$ 的下标分别为 $i$ 和 $j$$ij$距离为 $d j-i$。两个端点每秒各向内推进 1 格中间需要覆盖的格子数是 $d-1$。令 $t$ 秒后左端覆盖到 $it$、右端覆盖到 $j-t$两端相遇中间无空位的条件是$$ it \ge j-t-1 \iff 2t \ge d-1 \iff t \left\lfloor\dfrac{d}{2}\right\rfloor $$所以相邻两个 $x$ 之间被填满的耗时为$$ \left\lfloor\dfrac{j-i}{2}\right\rfloor $$整体耗时 最大相邻间距 ÷ 2对固定值 $x$把环形数组按 $x$ 的出现位置切成若干段每一段都由两端的 $x$ 向内扩散填充段之间互不影响。因此整个数组被 $x$ 完全覆盖的耗时等于所有相邻 $x$ 间距中最大者除以 2向下取整。枚举不同的 $x$更新答案的最小值即可。四、环形数组的破环处理提示 3用哈希表统计相同值的下标题解提示 3 给出的第一步是用哈希表把相同数字的下标聚在一起统计所有相同数字的下标记到一个哈希表 $\textit{pos}$ 中。即对每个值 $x$维护其所有出现位置 $pos[x] [p_1, p_2, \dots, p_k]$严格递增。首尾相邻环形 gap 公式本题数组是环形的所以 $pos[x]$ 中第一个下标 $p$ 与最后一个下标 $q$ 在环上也是相邻的。它们之间的环形间距为 $n-(q-p)$对应耗时为$$ \left\lfloor\dfrac{n-(q-p)}{2}\right\rfloor $$也就是说在计算相邻间距时不能只算 $p_2-p_1, \dots, p_k-p_{k-1}$还必须补上跨越数组末尾回到开头的这一段 $n-qp$。追加 $pn$ 的破环技巧题解给出了一个非常优雅的等价写法也可以在 $\textit{pos}[x]$ 列表末尾添加一个 $pn$就可以转换成非环形数组处理了。把首元素加上 $n$ 后追加到列表末尾得到$$ [p_1, p_2, \dots, p_k, p_1n] $$此时相邻差序列 $p_2-p_1, \dots, p_k-p_{k-1}, (p_1n)-p_k$ 恰好完整覆盖了环上所有相邻对最后一项等价于 $n-qp$问题就退化成了普通的线性相邻间距求最大值。整体算法流程如下扫描nums用哈希表pos记录每个值出现的下标列表对每个列表a补上首元素加 $n$ 的虚拟后继或等价地初始化mx n - a[len(a)-1] a[0]求相邻差的最大值mx则该值全覆盖耗时 mx / 2向下取整答案取所有值耗时的最小值。注意ans初始化为 $n$ 是一个安全的做法任何值覆盖整个数组的耗时都不会超过 $\lfloor n/2 \rfloor$以 $n$ 作为上界初值不会影响最小值的正确性。五、四语言完整实现以下代码完整继承自 README.md其中 Go 版本与仓库中的 c.go 逐行一致。Python3class Solution: def minimumSeconds(self, nums: List[int]) - int: pos defaultdict(list) for i, x in enumerate(nums): pos[x].append(i) ans n len(nums) for a in pos.values(): a.append(a[0] n) mx max(j - i for i, j in pairwise(a)) ans min(ans, mx) return ans // 2 # 最后再除 2Javaclass Solution { public int minimumSeconds(ListInteger nums) { int n nums.size(); MapInteger, ListInteger pos new HashMap(); for (int i 0; i n; i) { pos.computeIfAbsent(nums.get(i), k - new ArrayList()).add(i); } int ans n; for (ListInteger a : pos.values()) { int mx n - a.get(a.size() - 1) a.get(0); for (int i 1; i a.size(); i) { mx Math.max(mx, a.get(i) - a.get(i - 1)); } ans Math.min(ans, mx); } return ans / 2; // 最后再除 2 } }Cclass Solution { public: int minimumSeconds(vectorint nums) { int n nums.size(); unordered_mapint, vectorint pos; for (int i 0; i n; i) { pos[nums[i]].push_back(i); } int ans n; for (auto [_, a] : pos) { int mx n - a.back() a[0]; for (int i 1; i a.size(); i) { mx max(mx, a[i] - a[i - 1]); } ans min(ans, mx); } return ans / 2; // 最后再除 2 } };Go仓库 c.go 中的实现func minimumSeconds(nums []int) int { pos : map[int][]int{} for i, x : range nums { pos[x] append(pos[x], i) } n : len(nums) ans : n for _, a : range pos { mx : n - a[len(a)-1] a[0] for i : 1; i len(a); i { mx max(mx, a[i]-a[i-1]) } ans min(ans, mx) } return ans / 2 // 最后再除 2 }三种语言以及 Go 中max/min内建函数的写法略有差异但核心逻辑完全一致mx先取环形跨越首尾的间距再依次与相邻差取最大值最后统一除 2。六、复杂度分析题解给出的复杂度为时间复杂度$O(n)$其中 $n$ 为nums的长度。构造哈希表扫描一遍数组是 $O(n)$随后对每个值的下标列表各遍历一次总长度仍是 $O(n)$每个下标恰好属于一个列表。空间复杂度$O(n)$哈希表pos中总共存储了 $n$ 个下标。空间上还可以做一个小优化除二操作可以推迟到最后统一进行如所有代码中的ans / 2因为最大值除二与除二后的最大值在这里等价能省去中途的整除运算。七、仓库工程化验证题解与测试数据互相印证测试文件与数据文件c_test.go 由copypasta/template/leetcode/generator_test.go自动生成它调用测试框架读取 c.txt 中的数据并逐条断言func Test_c(t *testing.T) { targetCaseNum : 0 // -1 if err : testutil.RunLeetCodeFuncWithFile(t, minimumSeconds, c.txt, targetCaseNum); err ! nil { t.Fatal(err) } }c.txt 中保存了 3 组官方示例输入与期望输出按行交替存放输入期望输出[1,2,1,2]1[2,1,3,3,2]2[5,5,5,5]0手工推演三组用例[1,2,1,2]$n4$pos[1][0,2]、pos[2][1,3]。以x1为例环形间距mx 4-20 2相邻差为2-02耗时为2/21x2同理为 1。答案1。✔[2,1,3,3,2]$n5$。pos[2][0,4]环形间距mx5-401相邻差4-04耗时 2pos[1][1]仅出现一次环形间距mx5-115耗时 2pos[3][2,3]相邻差 1、环形间距 4耗时 2。答案2。✔[5,5,5,5]所有元素已经相等pos[5][0,1,2,3]的所有间距均为 1mx1耗时为1/20。✔ 这与直觉一致无需任何操作。测试运行框架的读取机制测试之所以能从文件读数据依赖仓库自研的 LeetCode 测试工具链。核心入口是 leetcode/testutil/leetcode.go 中的RunLeetCodeFuncWithFile读取文件后先做trimSpaceAndEmptyLine清洗得到非空行序列通过反射reflect.TypeOf(f)获取被测函数的参数个数fNumIn与返回值个数fNumOut据此把每fNumIn fNumOut行视为一组用例将用例交给RunLeetCodeFuncWithExamples用parseRawArray解析方括号包裹的数组输入再逐组与期望输出比对。因此只要把c.go中的minimumSeconds函数签名保持为一个[]int入参、一个int返回值新增测试数据时只需往 c.txt 追加输入行 期望输出行即可框架会自动完成解析与断言。八、本地运行验证仓库以github.com/EndlessCheng/codeforces-go为模块名见 go.modGo 1.23在仓库根目录执行go test ./leetcode/biweekly/110/c/ -run Test_c -v即可用 c.txt 中的三组数据验证minimumSeconds的实现。若临时修改 c_test.go 中的targetCaseNum为某个正数如1还可以实现先只跑指定用例、通过后自动跑全部用例的调试流程——这是该测试框架为调试单条用例设计的特性。九、算法复盘与题型延伸关键点小结枚举最终值利用值集合只减不增的性质把目标收敛到原数组中的某个数扩散模型相同值多处同时扩散段与段独立耗时由最大相邻间距决定环形处理floor((n-(q-p))/2)直接处理首尾相邻或追加pn破环成链两种写法殊途同归除二时机先取最大间距最后统一除以 2。边界情况数组初始即全相等某个值的间距全为 1答案为 0某值仅出现一次环形间距为 $n$耗时 $\lfloor n/2 \rfloor$等价于单源覆盖整个环$n1$只有一个元素答案为 0。分类归属本题在官方题解的分类题单中属于思维与贪心类题目解题脉络与以下方向一致贪心算法基本贪心策略 / 反悔 / 区间 / 字典序 / 数学 / 思维 / 脑筋急转弯 / 构造数学算法数论 / 组合 / 概率期望 / 博弈 / 计算几何 / 随机算法中的思维分支。这类扩散 / 传染 / 距离取半的模型在竞赛中很常见核心是先观察最终状态的唯一候选来源再对候选逐个求最大瓶颈最后用枚举 预处理降到线性复杂度。掌握破环成链 相邻间距取半的组合拳可以快速迁移到其他环形数组问题中。参考资源均在当前仓库内题解文档、Go 实现、单测文件、测试数据、测试运行框架、项目模块配置。赞分享科学计算【免费下载链接】codeforces-go算法竞赛模板库 by 灵茶山艾府 项目地址https://gitcode.com/GitHub_Trending/co/codeforces-go点击查看免费下载相关推荐Mistral架构与哲学对话的完美融合OpenHermes-2.5-Strix-Philosophy-7B技术原理剖析Mistral架构与哲学对话的完美融合OpenHermes 2.5 Strix Philosophy 7B技术原理剖析 OpenHermes 2.5 StriLeetCode 1929 Concatenation of Array 数组拼接双循环与索引映射两种解法及多语言实现剖析LeetCode 1929 Concatenation of Array 数组拼接双循环与索引映射两种解法及多语言实现剖析 本篇技术指南围绕 LeetCode示例工程教程LeetCode 215 数组中的第 K 个最大元素最小堆与 QuickSelect 多语言解法全解leetcode 仓库实战LeetCode 215 数组中的第 K 个最大元素最小堆与 QuickSelect 多语言解法全解leetcode 仓库实战 本文围绕 LeetCode示例工程教程上一篇ImageNet21K模型库深度测评8大预训练模型性能对比下一篇哈希与盐值保护CyberSecurity课程中的密码安全最佳实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表