给出了两个整数数组,我们必须找到将一个数组转换为另一个数组的最小操作数。
操作如下:
如果我们将数组的元素减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
答案 0 :(得分:3)
令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])(或等效地abs(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都是非负的。
请注意,其中任何一个都没有选择:如果存在解决方案,则该操作的排序是唯一的。
答案 1 :(得分:1)
首先将每个元素更改为否定它到达每个目标的距离(即从初始数组中减去最终数组中的每个元素)。然后我们只需得到全0。
要做到这一点,请继续降低最大值(heap可能是个好主意)。一旦所有数字都变为正数,就没有解决方案。
请注意,您不必将数字减少一个。您可以安全地将它一直减少到0(如果它为负,它仍然可以减1)或最多(it's value + minimum's value)/2
(因此它们会在中间相遇)< / p>
2元素数组[a,b]
仅在a = -b
时才有效。
示例:强>
对于3 2 2
到4 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
我们已经完成了。
答案 2 :(得分:0)
这非常简单,因为您只询问了最小操作数。由于您没有要求通用算法来实际计算沿途的步骤,因此如果您只是检查操作的每个步骤会发生什么,您可以在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
那么我们如何处理这个delta和?好吧,如果对你的例子给予足够的关注,你会注意到你得到的数字5不仅仅是一个随机的巧合! [4,5,3]的总和为12,[3,2,2]的总和为7.两个总和之间的差值为5.如果你还记得,长度为3的数组为delta_sum
总是会+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的数组添加一个特殊情况来解决它。
我们基本上想做的是:
(B[0] - A[0])
的绝对值。None
或出现错误,因为无法解决问题。例如[1,1] - &gt; [2,2],如评论中所述我们的几乎完成的代码结果如下:
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。在这种情况下,我们返回否定次操作(这很可能在概念上和实际上都是不可能的),我们可能希望返回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并且sums的差值是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