📌  相关文章
📜  将所有大小为 K 的子数组转换为单个元素所需的最低成本(1)

📅  最后修改于: 2023-12-03 14:53:50.836000             🧑  作者: Mango

将所有大小为 K 的子数组转换为单个元素所需的最低成本

问题描述

给定一个大小为N的数组A和一个正整数K,定义以下操作:

  1. 选择一个大小为K的子数组
  2. 将该子数组中的所有元素替换为子数组中的最大值 你可以执行以上操作任意次,求将整个数组A中的所有大小为K的子数组转换为单个元素所需的最低操作成本。
解决思路

对于一个大小为K的子数组,我们可以用一个值表示其内的所有元素。因此我们首先将整个数组按照K个元素一组分下来。 这样就得到了一个大小为N/K的新数组B,B中的元素B[i]表示原数组A中第iK个元素开始的K个元素对应的那个值。

考虑如何将这个新数组B中的所有元素转换为一个单个元素。假设$x$是数组$B$中所有元素的最大值。那么对于$B$中的任意一个元素$v$,我们可以这样变换:

$$ cost(v,x) = \sum_{i=1}^K (x-v[i]) = Kx - \sum_{i=1}^K v[i] $$

其中$v[i]$表示数组$v$中的第$i$个元素。我们将$v$数组中的所有元素都替换成$x$,操作成本就是$cost(v,x)$。

这样,对于新数组$B$中的每个元素,我们都可以计算出它到最大值$x$的操作成本。 题目要求的就是将整个数组A中的所有大小为K的子数组转换为单个元素所需的最低操作成本。 等价于将新数组B中的所有元素转化为同一个元素,求这个过程所需的最小操作成本。

而这个问题就是一个最小生成树问题。 具体的,我们将所有元素看做图中的节点(包括最大值$x$),将元素之间的操作成本看做相连的边的权值, 这样我们就得到了一个完全图,其中的最小生成树就是我们所求的答案。

代码实现

下面是Python3的完整代码实现:

from typing import List
from heapq import heappop, heappush

def minimum_cost_to_merge_subarrays(nums: List[int], k: int) -> int:
    n = len(nums)
    b = [max(nums[i:i+k]) for i in range(0, n, k)]
    x = max(b) # 元素最大值
    edges = []
    for v in b:
        cost = k * x - sum([v] * k)
        edges.append((v, x, cost))
    for i in range(len(b)):
        for j in range(i+1, len(b)):
            cost = k * x - sum([b[i], b[j]])
            edges.append((b[i], b[j], cost))
    return kruskal(b+[x], edges)

def kruskal(nodes, edges):
    parent = {node: node for node in nodes}
    size = {node: 1 for node in nodes}
    edges.sort(key=lambda x: x[2])
    res = 0
    for a, b, c in edges:
        pa = find_parent(a, parent)
        pb = find_parent(b, parent)
        if pa != pb:
            res += c
            union(pa, pb, parent, size)
    return res

def find_parent(x, parent):
    if parent[x] != x:
        parent[x] = find_parent(parent[x], parent)
    return parent[x]

def union(a, b, parent, size):
    if size[a] < size[b]:
        a, b = b, a
    parent[b] = a
    size[a] += size[b]
时间复杂度

对于大小为N的原数组,时间复杂度为$O(Nlog(N/K))$。