LeetCode 1354. Construct Target Array with Multiple Sums
原题链接
困难
作者:
JasonSun
,
2020-02-18 10:33:56
,
所有人可见
,
阅读 1053
Algorithm (Euclidean Algorithm + Heap)
- Note that at any given round $i$ of replacement, $\max A$ is the number that got replaced in round $i-1.$ For example, for input array
[1, 2, 3]
in round 1, possible round 2 candidates are [6, 2, 3]
, [1 ,6 ,3]
, and [1, 2, 6]
.
- Because the rest of the element in $A$ in round $i$ is the same as those in round $i-1,$ we can find out the number that got replaced in round $i-1$ in $O(1)$ using the sum of $A$ in round $i$. To put it abstractly, we have
\begin{align}
\mathrm{sum}(A^{\text{round}(k)}) & =\sum_{i=0}^{n-1}A_{i}^{\text{round}(k)}=\sum_{i=0,i\neq\text{replaced}}^{n-1}A_{i}^{\text{round}(k-1)}+\sum_{i=0}^{n-1}A_{i}^{\text{round}(k-1)},\\
\max(A^{\text{round}(k)}) & =\sum_{i=0}^{n-1}A_{i}^{\text{round}(k-1)},
\end{align}
from which we have
\begin{align}
A_{\text{replaced}}^{\text{round}(k-1)} & =\sum_{i=0}^{n-1}A_{i}^{\text{round}(k-1)}-\sum_{i=0,i\neq\text{replaced}}^{n-1}A_{i}^{\text{round}(k-1)}\\
& =\max(A^{\text{round}(k)})-(\mathrm{sum}(A^{\text{round}(k)})-\max(A^{\text{round}(k)}))\label{eq:1354-1}\tag{1}
\end{align}
- So suppose there is way to transform the input
ones
into $A$; there must exits a way to back transform $A$ into ones
using the \eqref{eq:1354-1}. Doing so using bruteforce search is too expensive because we need to query the max and sum of $A^{\text{round}(k)}$ for all possible rounds $k$. To speed things up:
- Since at each step of the back-transform process we only change the $A^{\text{round}}$ by one element,
priority_queue
could be used to update $\max A^{\text{round}(k)}$ efficiently.
- Also note that once $A_{\text{replaced}}^{\text{round}(k-1)}$ has been calculated using \eqref{eq:1354-1}, $\text{sum}(A^{\text{round}(k-1)})$ could be calculated using $\text{sum}(A^{\text{round}(k)})$ and $\max(A^{\text{round}(k)})$ as follows:
\begin{align}
\text{sum}(A^{\text{round}(k-1)}) & =\sum_{i=0}^{n-1}A_{i}^{\text{round}(k-1)}=\sum_{i=0,i\neq\text{replaced}}^{n-1}A_{i}^{\text{round}(k-1)}+A_{\text{replaced}}^{\text{round}(k-1)}\\
& =\text{sum}(A^{\text{round}(k)})-\max(A^{\text{round}(k)})+A_{\text{replaced}}^{\text{round}(k-1)}.
\end{align}
- In fact, the representation $A_{\text{replaced}}^{\text{round}(k-1)}$ is not unique. It is possible that $\max(A^{\text{round}(k)})$ is many times of $(\text{sum}(A^{\text{round}(k)})-\text{max}(A^{\text{round}(k)})).$ In this case, we can find the minimum of all possible representations of $A_{\text{replaced}}^{\text{round}(k-1)}$ instead of a random one. One quick way to do this is to use the following update formulae: $$A_{\text{replaced}}^{\text{round}(k-1)}=\max(A^{\text{round}(k)})\mod(\mathrm{sum}(A^{\text{round}(k)})-\max(A^{\text{round}(k)})).\label{eq:1354-2}\tag{2}$$ The correctness of this is guaranteed by the correctness of the classical Euclidean algorithm. We skip it here, but we instead give an example to demonstrate the point. Suppose our $A^{\text{round}(k)}=[10,3].$ Then using \eqref{eq:1354-1} we have $A^{\text{round}(k-1)}=[7,3].$ On the other hand, using \eqref{eq:1354-2} we have $A^{\text{round}(k-1)}=[1,3].$ This is indeed true, because a possible transforming sequence is $[1,3]\rightarrow[4,3]\rightarrow[7,3]\rightarrow[10,3]$.
- We return
true
if we can back-transform $A$ into ones
. On the other hand, if at any given round, we have $A_{\text{replaced}}$ is a negative number, we return false
.
- For implementation detail, we bundle
priority_queue
and $\text{sum}(A)$ and $\max(A)$ into one single state
record type and maintain the following state invariant: at any given time, the priority queue contains the input array at that time, and $\text{sum}(A)$ is the sum of that array, and $\max(A)$ the max. Then the back-transform process could be implemented as a function of the state. It is bounded to terminate because at each time $\max(A)$ is strictly decreasing.
- Our solution is inspired by
lee215
and Yaang
(who provided an example justifying the usage of modulo) on LeetCode. Shout out to both of them!
Code (Cpp17)
class Solution {
public:
bool isPossible(vector<int>& target) {
using int64 = long long;
const auto n = std::size(target);
struct state_t {
std::priority_queue<int64> PQ;
int64 acc_sum;
int64 acc_max;
};
auto prepare_initial_state = [&] {
// O(n) build
const auto PQ = std::priority_queue<int64>(std::begin(target), std::end(target));
const auto acc_sum = std::accumulate(std::begin(target), std::end(target), 0LL);
const auto acc_max = *std::max_element(std::begin(target), std::end(target));
return state_t{PQ, acc_sum, acc_max};
};
auto ensure_state_invariant = [&](state_t* state) {
auto& [PQ, acc_sum, acc_max] = *state;
if (std::size(PQ) == n - 1) {
const auto curr_num = acc_max;
const auto prev_num = acc_max % (acc_sum - acc_max);
PQ.push(prev_num);
acc_sum = acc_sum - curr_num + prev_num;
acc_max = PQ.top();
}
};
const auto solution = [&] {
auto state = prepare_initial_state();
std::function<bool(state_t*)> go = [&](state_t* state) {
auto& [PQ, acc_sum, acc_max] = *state;
if (acc_max == 1)
return true;
else if (acc_max <= acc_sum - acc_max)
return false;
else
return (PQ.pop(), ensure_state_invariant(state), go(state));
};
return go(&state);
}();
return solution;
}
};
latex + 英文帝
三库!
well down