AI 刷题 85. 数列差异的最小化 题解 | 豆包MarsCode AI刷题

180 阅读3分钟

image.png

题目要求我们最小化一个公式:

∣(𝑎[𝑖]−𝑏[𝑗])2−𝑘2∣∣(a[i]−b[j])2−k2∣

其中,𝑎[𝑖]a[i] 和 𝑏[𝑗]b[j] 分别是两个数列 𝑎a 和 𝑏b 中的元素,且公式的目标是选择一个 𝑎[𝑖]a[i] 和一个 𝑏[𝑗]b[j],使得这个公式的值最小。

思路分析

我们需要计算每对 (𝑎[𝑖],𝑏[𝑗])(a[i],b[j]) 的值:

𝑓(𝑖,𝑗)=∣(𝑎[𝑖]−𝑏[𝑗])2−𝑘2∣f(i,j)=∣(a[i]−b[j])2−k2∣

其中:

  • (𝑎[𝑖]−𝑏[𝑗])2(a[i]−b[j])2 是两个数的差的平方,表示两个数的差异;
  • 𝑘2k2 是常数,表示与这个差的平方的关系。

显然,公式中最小化的目标是让 (𝑎[𝑖]−𝑏[𝑗])2(a[i]−b[j])2 尽可能接近 𝑘2k2,即让差的平方尽可能接近 𝑘2k2。

关键优化点

由于计算每对 (𝑎[𝑖],𝑏[𝑗])(a[i],b[j]) 的结果需要 𝑂(𝑛×𝑚)O(n×m) 的时间复杂度,对于 𝑛,𝑚n,m 可以达到 105105,这个做法显然不可行。我们需要利用一些优化技巧来降低复杂度。

数学分析

目标是最小化:

𝑓(𝑖,𝑗)=∣(𝑎[𝑖]−𝑏[𝑗])2−𝑘2∣f(i,j)=∣(a[i]−b[j])2−k2∣

可以重写为:

𝑓(𝑖,𝑗)=∣(𝑎[𝑖]−𝑏[𝑗]−𝑘)×(𝑎[𝑖]−𝑏[𝑗]+𝑘)∣f(i,j)=∣(a[i]−b[j]−k)×(a[i]−b[j]+k)∣

这是一个关于 𝑎[𝑖]a[i] 和 𝑏[𝑗]b[j] 的差的平方项,因此我们可以通过对 𝑎[𝑖]−𝑏[𝑗]a[i]−b[j] 进行排序来优化问题。

策略

  1. 计算差值: 设 𝑑=𝑎[𝑖]−𝑏[𝑗]d=a[i]−b[j],那么我们需要最小化 ∣𝑑2−𝑘2∣∣d2−k2∣。这里的问题转化为在差值 𝑑d 之中寻找使得 𝑑2d2 最接近 𝑘2k2 的差值 𝑑d。

  2. 排序与二分查找

    • 对数组 𝑎a 和 𝑏b 进行排序。
    • 对于每个 𝑎[𝑖]a[i],我们希望找到最接近 𝑎[𝑖]−𝑘a[i]−k 和 𝑎[𝑖]+𝑘a[i]+k 的 𝑏[𝑗]b[j] 值。为了高效查找,排序和二分查找是一个有效的策略。
  3. 最小化距离

    • 使用二分查找,快速找到与目标 𝑎[𝑖]−𝑘a[i]−k 或 𝑎[𝑖]+𝑘a[i]+k 最接近的 𝑏[𝑗]b[j],这样可以有效地计算出最小的差值。

具体实现步骤

  1. 对数组 𝑏b 进行排序。
  2. 对每个 𝑎[𝑖]a[i] 使用二分查找,找到最接近 𝑎[𝑖]−𝑘a[i]−k 和 𝑎[𝑖]+𝑘a[i]+k 的 𝑏[𝑗]b[j]。
  3. 计算并更新最小的结果。

代码解释

  1. 排序

    • 我们首先对数组 𝑏b 进行排序,这样可以利用二分查找来快速定位最接近 𝑎[𝑖]−𝑘a[i]−k 和 𝑎[𝑖]+𝑘a[i]+k 的值。
  2. 二分查找

    • 对每个 𝑎[𝑖]a[i],我们计算目标值 𝑎[𝑖]−𝑘a[i]−k 和 𝑎[𝑖]+𝑘a[i]+k,然后使用 bisect_left 来找到数组 𝑏b 中最接近这两个目标值的位置。
    • 对于每个目标值,我们检查二分查找结果的当前位置及其前后位置,计算与目标值 𝑘2k2 的差异,并更新最小值。
  3. 时间复杂度

    • 排序 𝑏b 数组的时间复杂度是 𝑂(𝑚log⁡𝑚)O(mlogm)。
    • 对于每个 𝑎[𝑖]a[i],我们进行二分查找,时间复杂度是 𝑂(log⁡𝑚)O(logm)。因此,总的时间复杂度是 𝑂(𝑛log⁡𝑚+𝑚log⁡𝑚)O(nlogm+mlogm),适合题目中给定的约束条件。

示例

输入:

Copy Code
3 3 2
1 4 7
2 3 8

输出:

Copy Code
1

解释:

  • 对于 𝑎[0]=1a[0]=1,我们查找最接近 1−2=−11−2=−1 和 1+2=31+2=3 的 𝑏[𝑗]b[j],最接近的是 𝑏[1]=3b[1]=3。
  • 对于 𝑎[1]=4a[1]=4,最接近的 𝑏[𝑗]b[j] 是 𝑏[1]=3b[1]=3 或 𝑏[2]=8b[2]=8。
  • 对于 𝑎[2]=7a[2]=7,最接近的 𝑏[𝑗]b[j] 是 𝑏[2]=8b[2]=8。

最终的最小值是 1。

总结

通过排序和二分查找的方法,我们能够在较大的输入规模下高效地计算出最小值。时间复杂度是 𝑂(𝑛log⁡𝑚+𝑚log⁡𝑚)O(nlogm+mlogm),在最大规模的情况下也是可行的。

image.png