Given an array target
of integers, you start with an array arr
of the same length, where every element is 1
. You are allowed to perform the following operation any number of times:
i
and set arr[i] = sum(arr)
(i.e., replace one element with the sum of the entire array).
Your task is to determine if it is possible to construct the target
array from arr
using this operation any number of times.
Key Constraints:
target
are positive integers.
At first glance, the problem seems to ask if we can build up to the target
array by repeatedly replacing elements with the sum of the current array. A brute-force approach might try all possible sequences of operations, but this quickly becomes infeasible for large arrays or large numbers.
Observing the operation closely, we realize that every time we perform it, one element becomes much larger, and the sum increases rapidly. This suggests that instead of simulating every operation forward, it might be easier to work backwards: can we reduce target
to an array of all ones by reversing the allowed operation?
This reversal leads to a key insight: at each step, the largest number in target
must have been formed by summing the previous array and replacing one element. Thus, we can try to "undo" this operation by repeatedly reducing the largest element by the sum of the rest.
To solve the problem efficiently, we use a max-heap (priority queue) to always access the largest element in target
. Here’s a step-by-step breakdown:
target
into a max-heap for quick access to the largest number.
max_elem
).rest_sum = total_sum - max_elem
).rest_sum == 1
, then we can always reach the target by repeatedly subtracting 1, so return True
.
rest_sum == 0
or max_elem <= rest_sum
, return False
(invalid scenario).
max_elem
must have been max_elem % rest_sum
(since in one step, we could have added rest_sum
multiple times).
False
.
True
.
Why a heap? Using a max-heap allows us to efficiently find and update the largest element in each step, which is crucial for performance.
Sample Input: target = [9, 3, 5]
Explanation: Each time, we "undo" the operation by reducing the largest number, eventually reaching all ones.
Brute-force approach: Would explore every possible sequence of operations, leading to exponential time complexity: O(k^n)
where k
is the average value and n
is the array length.
Optimized approach (heap-based):
O(\log n)
.O(\log S)
where S
is the sum of array elements.O(n \log n + k \log n)
where k
is the number of reduction steps.
O(n)
for the heap.
The key insight is to simulate the process in reverse using a max-heap, always reducing the largest element by the sum of the rest, and efficiently checking for invalid configurations. This transforms what could be an exponential-time problem into a highly efficient solution. The use of heaps and modulo arithmetic makes the approach both elegant and practical for large inputs.
import heapq
class Solution:
def isPossible(self, target):
total = sum(target)
target = [-x for x in target]
heapq.heapify(target)
while True:
largest = -heapq.heappop(target)
rest = total - largest
if largest == 1 or rest == 1:
return True
if rest == 0 or largest <= rest:
return False
x = largest % rest
if x == 0:
return False
heapq.heappush(target, -x)
total = rest + x
#include <queue>
#include <vector>
using namespace std;
class Solution {
public:
bool isPossible(vector<int>& target) {
long long total = 0;
priority_queue<int> pq;
for (int num : target) {
pq.push(num);
total += num;
}
while (true) {
int largest = pq.top(); pq.pop();
long long rest = total - largest;
if (largest == 1 || rest == 1) return true;
if (rest == 0 || largest <= rest) return false;
int x = largest % rest;
if (x == 0) return false;
pq.push(x);
total = rest + x;
}
}
};
import java.util.*;
class Solution {
public boolean isPossible(int[] target) {
PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
long total = 0;
for (int num : target) {
pq.add(num);
total += num;
}
while (true) {
int largest = pq.poll();
long rest = total - largest;
if (largest == 1 || rest == 1) return true;
if (rest == 0 || largest <= rest) return false;
int x = (int)(largest % rest);
if (x == 0) return false;
pq.add(x);
total = rest + x;
}
}
}
class MaxHeap {
constructor(arr) {
this.heap = arr.slice();
this.heapify();
}
heapify() {
this.heap.sort((a, b) => b - a);
}
pop() {
return this.heap.shift();
}
push(val) {
this.heap.push(val);
this.heapify();
}
size() {
return this.heap.length;
}
}
var isPossible = function(target) {
let total = target.reduce((a, b) => a + b, 0);
let heap = new MaxHeap(target);
while (true) {
let largest = heap.pop();
let rest = total - largest;
if (largest === 1 || rest === 1) return true;
if (rest === 0 || largest <= rest) return false;
let x = largest % rest;
if (x === 0) return false;
heap.push(x);
total = rest + x;
}
};