给你一个整数数组 target
。一开始,你有一个数组 A
,它的所有元素均为 1 ,你可以执行以下操作:
x
为你数组里所有元素的和0 <= i < target.size
的任意下标 i
,并让 A
数组里下标为 i
处的值为 x
。如果能从 A
开始构造出目标数组 target
,请你返回 True ,否则返回 False 。
示例 1:
输入:target = [9,3,5]
输出:true
解释:从 [1, 1, 1] 开始
[1, 1, 1], 和为 3 ,选择下标 1
[1, 3, 1], 和为 5, 选择下标 2
[1, 3, 5], 和为 9, 选择下标 0
[9, 3, 5] 完成
示例 2:
输入:target = [1,1,1,2]
输出:false
解释:不可能从 [1,1,1,1] 出发构造目标数组。
示例 3:
输入:target = [8,5]
输出:true
提示:
N == target.length
1 <= target.length <= 5 * 10^4
1 <= target[i] <= 10^9
解题思路
这个问题可以从后向前处理,每次取出目标数组中的最大值,那么这个最大值必然是上一次数组的和替换后得到的。我们假设数组和为 s s s,而上一次数组的和为 p r e pre pre,那么上一次被替换的数字大小为 p r e − ( s − p r e ) = 2 ∗ p r e − s pre-(s-pre)=2*pre-s pre−(s−pre)=2∗pre−s,然后这个数放入数组中继续迭代下去。如果最大值为负数,那么表示失败;如果最大值为1
,那么表示成功。
例如,第一个例子,此时的最大值为9
,可以计算出替换前的数为2*9-17=1
,将1
放入数组,取出下一个最大值5
继续计算。
由于每次都取最大值,所以我们可以使用最大堆处理。
class Solution:
def isPossible(self, target: List[int]) -> bool:
q, s = [], 0
for i in target:
heapq.heappush(q, -i)
s += i
while True:
pre = -heapq.heappop(q)
if pre == 1:
return True
if pre*2 - s < 0:
return False
heapq.heappush(q, s - pre*2)
s = pre
但实际上上面这个写法会超时,对于这样的例子[1e9, 1]
。
很容易发现问题所在,当一个数非常大的时候减去其他非常小的数的和,结果依旧是最大值。那么可以通过取模计算上一次被替换的数字大小 p r e % ( s − p r e ) pre\%(s-pre) pre%(s−pre)。
此时的边界条件也需做一点调整,如果 p r e < s pre < s pre<s或者 p r e % s = 0 pre\%s=0 pre%s=0说明无解;如果 p r e = 1 pre=1 pre=1或者 s = 1 s=1 s=1说明有解。
class Solution:
def isPossible(self, target: List[int]) -> bool:
q, s = [], 0
for i in target:
heapq.heappush(q, -i)
s += i
while 1:
pre = -heapq.heappop(q)
s -= pre
if pre == 1 or s == 1:
return True
if pre < s or pre % s == 0:
return False
pre %= s
s += pre
heapq.heappush(q, -pre)
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!