ARTICLE DETAIL

资讯详情

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

LeetCode-Go 题解精读:1818. Minimum Absolute Sum Difference(最小绝对差值和)

LeetCode-Go 题解精读:1818. Minimum Absolute Sum Difference(最小绝对差值和) LeetCode-Go 题解精读1818. Minimum Absolute Sum Difference最小绝对差值和【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go导读本文围绕 LeetCode 第 1818 题「Minimum Absolute Sum Difference最小绝对差值和」展开完整解析题目定义、收益模型推导与 Go 语言实现。题目要求在只允许替换nums1中至多一个元素的条件下最小化两个数组对应位置绝对差的总和属于「枚举 数学变换」类型的经典问题。读完本文你将掌握绝对差值和问题的数学建模方法、将最小化总和转化为最大化替换收益 Δ的推导过程以及本仓库 LeetCode-Go 中该题解的具体实现、剪枝细节与测试用例验证方式。题目描述给定两个正整数数组nums1和nums2长度均为n。数组nums1与nums2的绝对差值和定义为对每个下标0 i n计算|nums1[i] - nums2[i]|并求和。你可以选用nums1中的任意一个元素去替换nums1中的至多一个元素以最小化绝对差值和。在完成替换之后返回最小的绝对差值和。由于答案可能很大需要对10^9 7取余后返回。其中|x|的定义为当x 0时取x当x 0时取-x。示例与预期输出示例 1输入nums1 [1,7,5], nums2 [2,3,5] 输出3 解释存在两种最优替换方案 - 将第二个元素替换为第一个[1,7,5] [1,1,5] - 将第二个元素替换为第三个[1,7,5] [1,5,5] 两种方案都能得到绝对差值和 |1-2| (|1-3| 或 |5-3|) |5-5| 3示例 2输入nums1 [2,4,6,8,10], nums2 [2,4,6,8,10] 输出0 解释nums1 与 nums2 完全相等无需任何替换绝对差值和即为 0。示例 3输入nums1 [1,10,4,4,2,7], nums2 [9,3,5,1,7,4] 输出20 解释将第一个元素替换为第二个[1,10,4,4,2,7] [10,10,4,4,2,7] 绝对差值和为 |10-9| |10-3| |4-5| |4-1| |2-7| |7-4| 20约束条件n nums1.lengthn nums2.length1 n 10^51 nums1[i], nums2[i] 10^5从约束可以看出n最大可达10^5这意味着数组规模较大而元素值域为1到10^5任意两个元素的差的绝对值最大为99999这一数值边界与题解实现中的哨兵值设计直接相关下文会展开说明。解题思路从数学建模到收益最大化第一步定义不替换时的绝对差值和如果不改变任何元素绝对差值和为$$\sum_{i0}^{n-1} \left | nums1[i] - nums2[i] \right |$$第二步建立替换一次的收益模型假设将nums1[i]替换为nums1[j]j可以是任意下标包括i本身那么位置i上的差值会从|nums1[i] - nums2[i]|变为|nums1[j] - nums2[i]|其余位置不受影响。替换后的总差值和为$$\sum_{i0}^{n-1} \left | nums1[i] - nums2[i] \right | - \left( \left | nums1[i] - nums2[i] \right | - \left | nums1[j] - nums2[i] \right | \right)$$记$$\Delta \left | nums1[i] - nums2[i] \right | - \left | nums1[j] - nums2[i] \right |$$则替换后的绝对差值和 原始总和 − Δ。第三步最小化总和等价于最大化 Δ题目要求返回最小的绝对差值和因此等价于在所有可能的替换方案中求 Δ 的最大值。其中 Δ 的含义非常直观用nums1[j]替换nums1[i]后位置i上的差值减少了多少。Δ 越大总和的削减越多。由此暴力解法便呼之欲出枚举每一个可能被替换的位置i再枚举nums1中的每一个候选替换元素nums1[j]计算对应的 Δ最终取最大值maxDiff答案即为$$\text{原始总和} - \max \Delta$$源码实现精读本仓库 LeetCode-Go 中该题的完整实现位于 1818. Minimum Absolute Sum Difference.go核心代码如下func minAbsoluteSumDiff(nums1 []int, nums2 []int) int { diff : 0 maxDiff : 0 for i, n2 : range nums2 { d : abs(nums1[i] - n2) diff d if maxDiff d { t : 100001 for _, n1 : range nums1 { maxDiff max(maxDiff, d-min(t, abs(n1-n2))) } } } return (diff - maxDiff) % (1e9 7) } func max(a, b int) int { if a b { return a } return b } func abs(a int) int { if a 0 { return a } return -a } func min(a, b int) int { if a b { return b } return a }主循环统计原始差值总和for i, n2 : range nums2 { d : abs(nums1[i] - n2) diff d ... }第一重循环遍历所有下标i以nums2为基准计算d |nums1[i] - nums2[i]|并累加到diff中。这一过程同时完成了两件事记录原始绝对差值和diff并为后续的收益计算提供每个位置的原始差值d。内层枚举与关键剪枝if maxDiff d { t : 100001 for _, n1 : range nums1 { maxDiff max(maxDiff, d-min(t, abs(n1-n2))) } }内层循环枚举所有候选替换元素n1若用n1替换nums1[i]位置i的新差值为abs(n1-n2)收益为d - abs(n1-n2)取历史最大值即可得到全局最大收益maxDiff。这里有一个非常关键的剪枝条件if maxDiff d。为什么可以这样剪枝因为收益的数学上界是d当新差值abs(n1-n2)取到最小值0即候选元素与nums2[i]完全相等时收益才达到上限d。因此若当前位置的原始差值d已经不大于当前已知的最大收益maxDiff那么即使在该位置上做到完美替换收益也不可能超过maxDiff内层枚举可以直接跳过。从实现看可以推断这个剪枝在数据差值递增、收益越算越大的场景下能把内层循环压缩掉大部分是这段暴力代码在多数测试数据下仍能较快通过的关键。哨兵值 100001 的含义内层循环中的t : 100001是一个值得注意的细节。由于题目约束1 nums1[i], nums2[i] 10^5任意两个元素的差的绝对值最大为99999恒小于100001因此min(t, abs(n1-n2))在合法输入范围内永远等于abs(n1-n2)t实质上充当了正无穷哨兵的角色等价于直接取abs(n1-n2)。从实现结构看可以推断作者用min统一处理候选差值的取值逻辑哨兵值保证了该式在题目约束内不会引入额外分支。需要说明的是仓库测试文件 1818. Minimum Absolute Sum Difference_test.go 中额外包含了一组超出题目约束值域的用例nums1 [1, 200000]、nums2 [200000, 1]期望输出199999该用例恰好覆盖了大数值差值的极端场景。结果取模return (diff - maxDiff) % (1e9 7)最终答案即原始总和 - 最大收益。由于maxDiff diff恒成立收益不会超过所有原始差值之和且d diffdiff - maxDiff非负直接对10^9 7取模即可与题目要求一致。代码中1e9 7作为无类型浮点常量在整数上下文中会被精确转换为1000000007语法合法。辅助函数max、min、abs三个辅助函数均为简单的分支判断实现没有任何依赖外部库代码风格与仓库中其他题解保持一致。复杂度分析时间复杂度最坏情况下为O(n²)。当每个位置的新差值d都大于当前maxDiff例如差值单调递增时每个下标都会触发完整的内层枚举当maxDiff较早达到较大值后后续位置大多被剪枝跳过实际运行远优于最坏情况。空间复杂度O(1)仅使用常数个额外变量未引入任何辅助数组或哈希表。测试用例验证仓库为该题编写了结构化的表格驱动测试见 1818. Minimum Absolute Sum Difference_test.go测试框架与其他题解一致定义para1818输入参数与ans1818期望答案结构体通过Test_Problem1818循环断言minAbsoluteSumDiff的输出与期望值一致不匹配时调用t.Fatalf报错。测试共覆盖 4 组用例输入 nums1输入 nums2期望输出说明[1, 7, 5][2, 3, 5]3题目示例 1存在两种等价最优替换[2, 4, 6, 8, 10][2, 4, 6, 8, 10]0题目示例 2无需替换[1, 10, 4, 4, 2, 7][9, 3, 5, 1, 7, 4]20题目示例 3[1, 200000][200000, 1]199999额外的大数值边界用例运行与验证方式该题解位于仓库leetcode/1818.Minimum-Absolute-Sum-Difference/目录下与仓库中所有题解一样按题号.题名组织。仓库根目录的 gotest.sh 提供了统一跑测试与覆盖率的方式go test -covermodeatomic -coverprofilecoverage.txt ./leetcode/...对单题验证可在对应目录下执行go test -v -run Test_Problem1818 ./leetcode/1818.Minimum-Absolute-Sum-Difference/仓库基于 Go 1.19见 go.mod运行前需确保本地 Go 环境版本不低于该要求。进阶思考从 O(n²) 到 O(n log n)在n 10^5的约束下暴力枚举的最坏复杂度为O(n²)当数据构造为最坏形态时仍可能偏慢。一个在算法层面常见并非本仓库实现的优化方向是排序 二分查找。由于收益 Δ 只关心与nums2[i]最接近的nums1元素可以将nums1排序后对每个nums2[i]使用二分查找定位其前驱与后继从中选出使|nums1[j] - nums2[i]|最小的候选从而把内层枚举从O(n)降到O(log n)整体复杂度优化至O(n log n)。这一思路是同类最小绝对差问题的通用套路读者可以在此基础上自行验证本仓库提供的O(n²) 剪枝实现正确性优先、代码直观是理解题目收益模型的最佳起点而二分优化版本则在极限数据下具备更强的性能保障。小结本题的核心价值在于一步漂亮的数学转化把替换至多一个元素使总和最小建模为计算每个位置的替换收益 Δ 并求最大值从而将问题化归为一次遍历统计 一次候选枚举。结合 LeetCode-Go 仓库的源码与测试读者可以完整掌握该题从题意、推导、实现到验证的全链路同时体会剪枝条件与哨兵值等工程细节在竞赛题解中的实际作用。【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表