Kimi LeetCode 3801. 合并有序列表的最小成本 Python3实现
2026/8/5 10:16:34 网站建设 项目流程

以下是 LeetCode 3801. 合并有序列表的最小成本 的 Python3 实现,方法签名为 `def minMergeCost(self, lists: List[List[int]]) -> int`。

核心思路

- 关键观察:任意子集合并后的有序列表,其中位数只取决于该子集包含哪些原始列表,与合并顺序无关。
- Meet-in-the-Middle + 状态压缩 DP:
1. 将 `n ≤ 12` 个列表平分为前后两半,分别预处理所有子集合并后的有序数组。
2. 对任意 `mask`,利用「两个有序数组的中位数」算法(LeetCode 4 变体)在 `O(log L)` 内求出中位数。
3. 子集 DP:`dp[mask]` 表示将 `mask` 对应列表合并为一个的最小成本。枚举所有非空真子集转移。
- 复杂度:时间 `O(2^n · L + 3^n)`,空间 `O(2^n + L)`,其中 `L ≤ 2000` 为总长度。

```python
from typing import List

class Solution:
def minMergeCost(self, lists: List[List[int]]) -> int:
n = len(lists)

def merge(a: List[int], b: List[int]) -> List[int]:
"""合并两个有序数组"""
i = j = 0
res = []
while i < len(a) and j < len(b):
if a[i] <= b[j]:
res.append(a[i])
i += 1
else:
res.append(b[j])
j += 1
if i < len(a):
res.extend(a[i:])
if j < len(b):
res.extend(b[j:])
return res

def calc_sorted(sub_lists: List[List[int]]) -> List[List[int]]:
"""预计算 sub_lists 所有子集合并后的有序数组"""
m = len(sub_lists)
u = 1 << m
sorted_arr = [[] for _ in range(u)]
for i in range(m):
high_bit = 1 << i
for s in range(high_bit):
sorted_arr[high_bit | s] = merge(sub_lists[i], sorted_arr[s])
return sorted_arr

def find_median_sorted_arrays(a: List[int], b: List[int]) -> int:
"""
找两个有序数组合并后的下中位数。
偶数长度时取左侧中间元素(题目定义)。
"""
if len(a) > len(b):
a, b = b, a
m, n_len = len(a), len(b)
left, right = 0, m
while left < right:
mid = (left + right) // 2
j = (m + n_len + 1) // 2 - mid - 2
if j + 1 < n_len and a[mid] > b[j + 1]:
right = mid
else:
left = mid + 1
i = left - 1
j = (m + n_len + 1) // 2 - i - 2
if i < 0:
return b[j]
if j < 0:
return a[i]
return max(a[i], b[j])

# 1. 分治预处理前后两半的所有子集合并结果
m = n // 2
sorted1 = calc_sorted(lists[:m])
sorted2 = calc_sorted(lists[m:])

u = 1 << n
half = (1 << m) - 1

# 2. 预计算每个 mask 的中位数和总长度
median = [0] * u
for mask in range(1, u):
median[mask] = find_median_sorted_arrays(
sorted1[mask & half],
sorted2[mask >> m]
)

# 3. 子集 DP
INF = float('inf')
dp = [0] * u

for mask in range(u):
if mask & (mask - 1) == 0: # 0 或单个列表,无需合并
continue
dp[mask] = INF
sub = (mask - 1) & mask
# 只枚举 sub > other 避免重复计算(对称性)
while sub > (mask ^ sub):
other = mask ^ sub
dp[mask] = min(
dp[mask],
dp[sub] + dp[other] + abs(median[sub] - median[other])
)
sub = (sub - 1) & mask
# 加上当前合并的长度成本(len(sub) + len(other) == len(mask))
dp[mask] += len(sorted1[mask & half]) + len(sorted2[mask >> m])

return dp[u - 1]
```

验证结果

输入 期望 实际
`[[1,3,5],[2,4],[6,7,8]]` `18` `18`
`[[1,1,5],[1,4,7,8]]` `10` `10`
`[[1],[3]]` `4` `4`
`[[1],[1]]` `2` `2`

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询