多次求和构造目标数组
难度:
标签:
题目描述
代码结果
运行时间: 30 ms, 内存: 21.1 MB
/*
* 思路:
* 使用Stream API来处理目标数组。虽然Stream在处理复杂逻辑时不如常规方法直观,但我们可以使用集合操作来实现逻辑。
* 1. 从目标数组中找到最大的元素,这个元素是由前一步的数组和构成的。
* 2. 将该元素减去数组和的其余部分,得到上一步的元素。
* 3. 如果新的元素为0或负数,则不可能构造目标数组,返回false。
* 4. 继续重复上述步骤,直到所有元素都变成1为止。
*/
import java.util.*;
import java.util.stream.Collectors;
public class SolutionStream {
public boolean isPossible(int[] target) {
if (target.length == 1) {
return target[0] == 1;
}
PriorityQueue<Integer> pq = new PriorityQueue<>(Comparator.reverseOrder());
long sum = Arrays.stream(target).asLongStream().sum();
pq.addAll(Arrays.stream(target).boxed().collect(Collectors.toList()));
while (true) {
int max = pq.poll();
sum -= max;
if (max == 1 || sum == 1) {
return true;
}
if (max < sum || sum == 0 || max % sum == 0) {
return false;
}
max %= sum;
sum += max;
pq.offer(max);
}
}
}
解释
方法:
题解使用了反向操作的思路,即从target数组反推回初始数组,看是否所有元素均能变为1。主要思路是使用最大堆(通过存储负数来使用Python的最小堆实现最大堆的效果),每次从堆中取出当前最大的元素,计算这个元素与其他元素总和的差,即是上一次操作后该位置的值。如果在任何时刻,最大元素值减去其他元素的总和小于1,说明无法通过加法操作得到该值,返回False。继续这个过程,直到所有元素变为1。这个方法利用了每次操作对数组的最大值影响最大的特性,从而反向模拟得到是否可行。
时间复杂度:
O(n log m) ,其中n是target数组的长度,m是target数组中元素的最大值。
空间复杂度:
O(n)
代码细节讲解
🦆
在反向操作中,为什么选择每次都从最大的元素开始处理?
▷🦆
算法中提到的`ceil((p - a) / rest)`计算是如何确定的?请解释其逻辑和作用。
▷🦆
如果最大元素减去其他元素的总和小于1,则返回False,这一步为什么是必要的,它在算法中起到什么作用?
▷🦆
在处理过程中,当最大值和第二大值相等时,为什么判断为无法进行操作,即返回False?
▷