Yonlif ответ неверный.
В Find subaray с заданной суммой решение у нас есть цикл, в котором мы выполняем подстановку.
while (curr_sum > sum && start < i-1)
curr_sum = curr_sum - arr[start++];
Так как нет обратного операторалогического И, мы не можем переписать эту строку и не можем использовать это решение напрямую.
Можно сказать, что мы можем пересчитать сумму каждый раз, когда увеличиваем нижнюю границу скользящего окна (что приведет нас кна O(n^2)
сложность времени), но это решение не будет работать (в конце я приведу пример кода и счетчика).
Вот решение методом грубой силы, которое работает в O(n^3)
unsigned int getSum(const vector<int>& vec, int from, int to) {
unsigned int sum = -1;
for (auto k = from; k <= to; k++)
sum &= (unsigned int)vec[k];
return sum;
}
void updateMin(unsigned int& minDiff, int sum, int target) {
minDiff = std::min(minDiff, (unsigned int)std::abs((int)sum - target));
}
// Brute force solution: O(n^3)
int maxSubArray(const std::vector<int>& vec, int target) {
auto minDiff = UINT_MAX;
for (auto i = 0; i < vec.size(); i++)
for (auto j = i; j < vec.size(); j++)
updateMin(minDiff, getSum(vec, i, j), target);
return minDiff;
}
Вот решение O(n^2)
в C ++ (благодаря BM ответ) Идея состоит в том, чтобы обновить текущую сумму вместо вызова getSum
длякаждые два показателя.Вам также следует взглянуть на ответ BM , поскольку он содержит условия для раннего пробоя.Вот версия C ++:
int maxSubArray(const std::vector<int>& vec, int target) {
auto minDiff = UINT_MAX;
for (auto i = 0; i < vec.size(); i++) {
unsigned int sum = -1;
for (auto j = i; j < vec.size(); j++) {
sum &= (unsigned int)vec[j];
updateMin(minDiff, sum, target);
}
}
return minDiff;
}
Здесь НЕ работает решение со скользящим окном: Это идея из ответа Йонлифа с предварительным вычислением суммы в O(n^2)
int maxSubArray(const std::vector<int>& vec, int target) {
auto minDiff = UINT_MAX;
unsigned int sum = -1;
auto left = 0, right = 0;
while (right < vec.size()) {
if (sum > target)
sum &= (unsigned int)vec[right++];
else
sum = getSum(vec, ++left, right);
updateMin(minDiff, sum, target);
}
right--;
while (left < vec.size()) {
sum = getSum(vec, left++, right);
updateMin(minDiff, sum, target);
}
return minDiff;
}
Проблема этого решения в том, что мы пропускаем некоторые последовательности, которые на самом деле могут быть лучшими.
Ввод: vector = [26,77,21,6]
, target = 5
.
Выход должен быть равен нулю при 77 & 21 = 5, но подход с скользящим окном не может найти его, поскольку он сначала будет рассматривать окно [0..3], а затем увеличить нижнюю границу, не имея возможности рассмотреть окно [1..2].
Если у кого-то есть линейное или логарифмическое решение, которое работает, было бы неплохо опубликовать.