如何高效求解数组配对后绝对差值和的最小值

千辰君_5334

千辰君_5334

2026-09-18

898人浏览

原创

如何高效求解数组配对后绝对差值和的最小值

本文介绍一种时间复杂度为 o(n log n) 的最优算法,用于在任意长度数组中选出不相交数对,使各对绝对差之和最小;核心思想是排序后利用前缀/后缀差分预处理,避免暴力枚举,尤其显著优化奇数长度数组的计算效率。

本文介绍一种时间复杂度为 o(n log n) 的最优算法,用于在任意长度数组中选出不相交数对,使各对绝对差之和最小;核心思想是排序后利用前缀/后缀差分预处理,避免暴力枚举,尤其显著优化奇数长度数组的计算效率。

在数组中将元素两两配对(不重复、全覆盖),并计算每对元素的绝对差值之和,目标是使该总和最小。观察可知:最优配对一定发生在排序后的相邻元素之间——因为若存在交叉配对(如 a

对于偶数长度数组,直接排序后按 arr[1]−arr[0] + arr[3]−arr[2] + ... 累加即可(因已升序,绝对值可省略)。但奇数长度时需舍弃一个元素,再对剩余偶数个元素做相邻配对。暴力做法是尝试删除每个元素并重算,时间复杂度达 O(n²),不可接受。

高效解法的关键洞察在于:删除不同位置元素所对应的配对方案,在符号分布上具有高度规律性。以排序后数组 [A, B, C, D, E, F, G](长度 7)为例,删除第 i 个元素后,剩余元素的最优相邻配对会自然形成固定符号模式:

删 A:     -B +C -D +E -F +G   → sum = (C−B) + (E−D) + (G−F)
删 B:   A -C +D -E +F -G       → sum = (C−A) + (E−D) + (G−F) ❌ 错误?注意:实际配对应为 (A,C)? 不对!

更严谨地,我们重新审视配对逻辑:
当删除索引 k 的元素后,左侧 k 个与右侧 n−1−k 个元素需各自内部配对。由于最优配对必为相邻,且总长度为偶数,实际形成的配对结构是:

  • k 为偶数(即左侧有偶数个),则左侧可完全配对(0–1, 2–3,…),右侧也偶数个,同样完全配对(k+1–k+2,…);
  • k 为奇数,则左侧剩奇数个 → 最右一个无法配对,必须与右侧最左一个配对,导致“跨段” —— 这会使分析复杂化。

但原答案提示了更简洁的视角:所有合法删除方案对应的差值表达式,本质上是对排序后数组的线性组合,系数仅取 {−1, 0, +1},且相邻方案间仅差常数项。经严格推导可得:

✅ 正确高效策略:

  1. 排序数组 arr
  2. 预处理两个数组:
    • left[i]arr[0..i] 中偶数长度前缀的最小配对和(即取 arr[0..i]i 为奇数时的 even_arr_sum);
    • right[j]arr[j..n−1] 中偶数长度后缀的最小配对和;
  3. 对每个可能的删除位置 k(0 ≤ k arr[k],则剩余部分被分为 arr[0..k−1]arr[k+1..n−1]。为使总长度为偶数,这两段长度奇偶性必须相同。因此:
    • k 为偶数 → 左段长 k(偶),右段长 n−1−k(因 n 奇 ⇒ n−1 偶 ⇒ n−1−k 偶),两段均可独立最优配对;
    • k 为奇数 → 两段均为奇数长,无法独立配对 → 必须将左段末与右段首“桥接”,即用 arr[k−1]arr[k+1] 配对,其余分别配对。

然而,更通用且实现简洁的方法是:利用动态规划或预处理前后缀,避免重复计算。但针对本题约束,最优实践是采用「符号累加差分法」——正如答案所提示:

对排序后数组 a[0..n−1],定义初始删除 a[0] 的和为 S₀ = Σ_{i=0}^{(n−3)/2} (a[2i+2] − a[2i+1])
则删除 a[k] 的和 Sₖ = Sₖ₋₁ − a[k−1] + a[k](需调整索引偏移,实际需分奇偶讨论)。

但为确保正确性与可读性,推荐以下稳健 O(n log n) 实现:

def smallest_sum(arr):
    arr = sorted(arr)
    n = len(arr)
    if n % 2 == 0:
        return sum(arr[i+1] - arr[i] for i in range(0, n, 2))

    # n is odd: precompute prefix and suffix even-length pair sums
    # left[i] = min sum for arr[0:i] (i must be even)
    left = [0] * (n + 1)
    for i in range(2, n + 1, 2):
        left[i] = left[i-2] + arr[i-1] - arr[i-2]

    # right[i] = min sum for arr[i:n] (n-i must be even)
    right = [0] * (n + 1)
    for i in range(n - 2, -1, -2):
        right[i] = right[i+2] + arr[i+1] - arr[i]

    # Try removing each element at index k
    ans = float('inf')
    for k in range(n):
        # After removing k, left part: [0, k), right part: [k+1, n)
        left_len = k
        right_len = n - 1 - k
        if left_len % 2 == 0 and right_len % 2 == 0:
            s = left[k] + right[k+1]
        elif left_len % 2 == 1 and right_len % 2 == 1:
            # bridge: pair arr[k-1] and arr[k+1], then rest
            if k > 0 and k  1 else 0) + (arr[k+1] - arr[k-1]) + (right[k+2] if k+2 <p>⚠️ 注意事项:  </p>
  • 该算法依赖排序,故时间复杂度主导项为 O(n log n);
  • 边界情况(如 n=1n=3)需单独验证,n=1 应返回 0(无可配对),n=3 时仅三种删除,可直接计算;
  • 实际应用中,可进一步合并奇偶逻辑,用统一 DP 状态 dp[i][p] 表示前 i 个元素、当前未配对数为 p(0 或 1)时的最小和,实现更普适的 O(n²) 解法(但本题 O(n log n) 已足够);
  • 所有配对均基于排序后相邻性,切勿在未排序数组上直接应用

综上,通过预处理前后缀配对和,我们成功将奇数长度问题的复杂度从 O(n²) 降至 O(n log n),兼顾正确性与工程实用性。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1531

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

3584

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1549

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

20357

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2527

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2587

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1063

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

576

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2003

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133万人学习