【问题标题】:find minimum number of operations找到最小操作数
【发布时间】:2013-10-09 16:53:27
【问题描述】:

给出了两个整数数组,我们必须找到将一个数组转换为另一个数组的最小操作数。

操作如下:

如果我们将数组的一个元素减 1,那么所有其他元素都会增加 1。

我们必须找到最小数量的这样的操作来改变一个数组到另一个..

示例 假设初始数组是 3 2 2
最终数组是 4 5 3

最少需要 5 次操作。

解释:3 2 2 -> 2 3 3 -> 3 4 2 -> 2 5 3 -> 3 4 4 -> 4 5 3

【问题讨论】:

  • 映射是 O(n),你想要小于 n 吗?
  • 如果做不到呢? {1,1} -> {2,2}
  • n-输入、m-神经元、n-输出的前馈多层神经网络也可以进行 nm + nm 计算。
  • @Shubham 我认为如果您删除带有解释的 cmets 并将它们作为示例移动到问题中会更好。否则,任何人阅读所有历史记录/能够帮助您的机会都非常小。
  • @ShubhamChawla - 你试过什么?

标签: algorithm dynamic-programming


【解决方案1】:

令 N 为数组的大小,A 和 B。对于 N=1,任何变换都是可能的,步数为 abs(A[0] - B[0])。对于 N=2,每个操作增加一个数字并减少另一个数字。那么为了存在一个解决方案,我们必须有 B[1] = A[1] - B[0] + A[0],并且操作数是 abs(A[0] - B[0]) (或等效绝对(A[1] - B[1]))。

对于 N > 2,考虑数组中所有元素的总和。每一步减1个元素,增加N-1个元素1个,所以总数增加N-2个。

因此,如果可以使用这样的操作将数组 A 转换为数组 B,那么步数将为 (sum(B) - sum(A)) / (N-2)。叫这个 T。

操作是通勤的,因此要计算转换是否可能,只需计算出每个元素递减多少次就足够了。如果第 i 个元素减少 n_i 次,则它会增加 T-n_i 次。所以 B[i] = A[i] - n_i + T - n_i,因此 n_i = (A[i] - B[i] + T) / 2。

这就是我们需要的一切:如果 (sum(B) - sum(A)) 可以被 N-2 整除,并且调用 T = (sum(B) - sum(A) / (N-2 ),我们还需要 A[i] - B[i] + T 可以被 2 整除并且对于每个 i 都是非负的。

请注意,这里没有任何选择:如果存在解决方案,那么它在操作的顺序上是唯一的。

【讨论】:

  • 如果 sum(A)==sum(B) 怎么办??
  • 以 1 2 3 和 3 2 1 为例
  • @ShubhamChawla 那么这是不可能的。没有解决办法。
  • @ShubhamChawla 我给出了答案中存在解决方案的一般条件。对于 1,2,3 和 3,2,1,我们有 T=0,并且 n_0 = (1 - 3) / 2 = -1,这是负数。因此没有解决办法。
  • @songlj 是的,你是对的。 N=1、2的情况有不同的解。我将这些添加到我的答案中。
【解决方案2】:

首先将每个元素更改为否定它必须到达每个目标的距离(即从初始数组中减去最终数组中的每个元素)。然后我们只需要得到全 0。

为此,请不断减小最大值(heap 在这里可能是个好主意)。一旦所有数字都变为正数,就没有解决方案。

请注意,您不必只是将数字减一。您可以安全地将它一直减少到 0(如果它是负数,它仍然可以减少 1)或最多 (it's value + minimum's value)/2(因此它们会在中间相遇)

2 元素数组 [a,b] 仅在 a = -b 时有效。

示例:

对于3 2 24 5 3,我们标准化为3-4 5-2 3-2 = -1 -3 -1

然后我们减少-1 给我们-2 -2 0
然后我们减少0 给我们-1 -1 -1
然后我们减少-1 给我们-2 0 0
然后我们减少0 给我们-1 -1 1
然后我们减少1 给我们0 0 0

我们完成了。

【讨论】:

    【解决方案3】:

    这非常简单,因为您只问了最少操作数是多少。由于您不需要通用算法来实际计算沿途的步骤,因此如果您只需检查操作的每个步骤发生的情况,您可以在 O(n) 时间内轻松完成此操作。

    首先,注意所有元素的总和在您对其执行操作时如何变化。让我们从简单的案例开始,然后再转向更复杂的案例。

    假设我们有一个大小为 1 的数组 [1],并且我们对单个元素执行操作。它变为 [0]。所以每次操作后数组的总和增加-1。

    现在假设我们有一个大小为 2 的数组 [1, 1] 并且我们针对两个元素中的任何一个执行操作。它将变为 [2, 0] 或 [0, 2]。所以每次操作数组的总和都会增加0。

    对于大小为 3 的数组呢? [1, 1, 1] 在执行以第一个元素为目标的操作后变为 [0, 2, 2]。

    也许您可以在这里看到公式,它是数组总和如何变化的概括,它取决于单个变量,即数组的长度!

    对于任何给定的数组 A,计算总和变化的公式是:

    delta_sum = len(A) - 2
    

    那么我们如何处理这个增量总和?好吧,如果对您的示例给予足够的关注,您会注意到您得到的数字 5 不仅仅是随机巧合! [4, 5, 3] 的和是 12,[3, 2, 2] 的和是 7。这两个和之间的差是 5。如果你还记得,delta_sum 对于长度为 3 的数组总是将是+1。那么如果我们只是这样做呢? (python示例)

    def minOperations(A, B):
        return (sum(B) - sum(A)) / (len(A) - 2)
    

    令人惊讶的是,这个简单的单行语句为我们提供了 大多数 数组 A 和 B 的正确答案,len(A) == len(B) 甚至像 A=[] 和 B=[] 这样的空数组也会返回 0来自这个函数,因为 0/-2 是 0。

    但是等等……我们的代码有一些问题!我们将一个数字除以len(A) - 2。如果len(A) - 2 == 0 怎么办?不幸的是,如果我们的delta_sum 为 0,我们将收到 ZeroDivisionError!我们如何解决这个问题?我们可以通过简单地为长度为 2 的数组添加一个特殊情况来修复它。

    我们真正想做的是:

    1. 如果两个数组完全相同,则返回 0。
    2. 如果两个数组的 sum 相同但元素不同,则返回 (B[0] - A[0]) 的绝对值。
    3. 否则返回None 或一些错误,因为无法解决。例如[1, 1] -> [2, 2] 如 cmets 中所述

    我们几乎完成的代码结果如下:

    def minOperations(A, B):
        if len(A) == 2: 
            if A == B: 
                return 0
            elif sum(A) == sum(B): 
                return abs(B[0] - A[0]) 
            else:
                return None
        return (sum(B) - sum(A)) / (len(A) - 2)
    

    不幸的是,我们仍然需要处理一些愚蠢的问题来完善我们的代码。

    其中一个问题是您有两个数组 A 和 B,完全不可能通过递减操作将 A 转换为 B。

    例如考虑 A = [-1] 和 B = [1] 的情况。仅使用您在问题中描述的递减运算符,就不可能将 A 转换为 B!我们的函数会巧妙地返回'-2。在这种情况下,如果我们返回 negative 数量的操作(这很可能在概念上和实际上都是不可能的),我们可能希望返回 None 或一些异常/错误。我们可以通过以下代码做到这一点。

    result = (sum(B) - sum(A)) / (len(A) - 2)
    return result if result >= 0 else None
    

    然后我们有另一个问题...如果数组 A = [1,2,3,4] 和数组 B = [1,2,3,5] 怎么办?由于我们的 delta_sum 为 2 并且总和的差为 1,我们将返回 1 / 2 整数除法,在 Python 中为 0...所以我们还需要检查我们的结果是否等价于整数,如果不是,我们是返回无效的答案。我们可以通过以下方式做到这一点:

    result = float((sum(B) - sum(A))) / (len(A) - 2)
        return int(result) if result >= 0 and result == int(result) else None
    

    为了使您的代码更加健壮,您还可以添加一个断言检查,以确保两个数组的长度在代码开头是相等的。

    assert(len(A) == len(B))
    

    我们完成的代码将如下所示:

    def minOperations(A, B):
        assert(len(A) == len(B))
        if len(A) == 2: 
            if A == B: 
                return 0
            elif sum(A) == sum(B): 
                return abs(B[0] - A[0]) 
            else:
                return None
        result = float((sum(B) - sum(A))) / (len(A) - 2)
        return int(result) if result >= 0 and result == int(result) else None
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-28
      • 2015-10-21
      • 1970-01-01
      • 2011-05-28
      • 2021-01-16
      • 2019-06-26
      • 2018-12-29
      相关资源
      最近更新 更多