问题
I got this problem on Hackerrank. https://www.hackerrank.com/challenges/playing-with-numbers/problem
Given an array of integers, you must answer a number of queries. Each query consists of a single integer, x and is performed as follows:
- Add x to each element of the array, permanently modifying it for any future queries.
- Find the absolute value of each element in the array and print the sum of the absolute values on a new line.
All I need to complete the following method,
static int[] solution(int[] arr, int[] queries)
Here, arr is the array with n elements
and queries contain all the x that I need to add with each value of the array arr and then get the absolute sum of the elements of arr. So the resultant array will be the same size as array queries, say that size is m. The method will return an array of m elements.
Below is my implementation.
static int[] solution(int[] arr, int[] queries)
{
int[] result = new int[queries.length];
for (int i = 0; i < queries.length; i++)
{
int total = 0;
for (int j = 0; j < arr.length; j++)
{
arr[j] += queries[i];
if (arr[j] > 0)
total += arr[j];
else
total -= arr[j];
}
result[i] = total;
}
return result;
}
It works fine, its complexity is O(mn), but I need to do it with a complexity of something O(nlog_m) or O(mlog_n) or close to that.
回答1:
ANSWER
Essentially, if you know how many numbers will be positive and how many will be negative, you can just multiply both of these counts by the accumulated query total (and *-1 for negatives).
Work out the total count for how many -/+ there are and the total sum for all these values at each step. E.g. add +1 to all until all negatives are positive, and add -1 to all until all positives are negative, store the results of each step (the -/+ counts and total sum of all -/+ values).
You can now reference the total sum and the total -/+ counts for each step to work out the result of each query.
You will also need to change the return type of both the playingWithNumbers method and the result array, from int to long!
static long[] playingWithNumbers(int[] arr, int[] queries) {
long[] results = new long[queries.length];
List<Integer> negatives = new ArrayList<>(arr.length);
List<Integer> positives = new ArrayList<>(arr.length);
long negativeSum = 0;
long positiveSum = 0;
for (int i : arr) {
if (i < 0) {
negatives.add(i);
negativeSum += i;
} else {
positives.add(i);
positiveSum += i;
}
}
int negativeCount = negatives.size();
int positiveCount = positives.size();
Collections.sort(negatives);
Collections.sort(positives);
Map<Integer, Integer> countMap = new HashMap<>(arr.length);
Map<Integer, Long> sumMap = new HashMap<>(arr.length);
long totalSum = positiveSum + (negativeSum * -1);
countMap.put(0, negativeCount);
sumMap.put(0, totalSum);
if (positiveCount != 0) {
long tmpTotalSum = totalSum;
int tmpNegativeCount = negativeCount;
int increment = negativeCount - positiveCount;
int index = 0;
for (int i = 1; i <= positives.get(positiveCount - 1) + 1; i++) {
while (index != positives.size() && positives.get(index) - i == -1) {
tmpNegativeCount++;
increment += 2;
index++;
}
tmpTotalSum += increment;
countMap.put(i * -1, tmpNegativeCount);
sumMap.put(i * -1, tmpTotalSum);
}
}
if (negativeCount != 0) {
long tmpTotalSum = totalSum;
int tmpNegativeCount = negativeCount;
int increment = positiveCount - negativeCount;
int index = negativeCount - 1;
for (int i = 1; i <= (negatives.get(0) - 1) * -1; i++) {
int incrementNxt = 0;
while (index != -1 && negatives.get(index) + i == 0) {
tmpNegativeCount--;
incrementNxt += 2;
index--;
}
tmpTotalSum += increment;
increment += incrementNxt;
countMap.put(i, tmpNegativeCount);
sumMap.put(i, tmpTotalSum);
}
}
int maxNegative = positiveCount != 0 ? (positives.get(positiveCount - 1) + 1) * -1 : 0;
int maxPositive = negativeCount != 0 ? ((negatives.get(0) - 1)) * -1 : 0;
int totalCount = positiveCount + negativeCount;
long accumulatedTotal = 0;
for (int i = 0; i < queries.length; i++) {
accumulatedTotal += queries[i];
if (accumulatedTotal >= maxNegative && accumulatedTotal <= maxPositive) {
results[i] = sumMap.get((int)accumulatedTotal);
} else if (accumulatedTotal < maxNegative) {
long extra = maxNegative - accumulatedTotal;
results[i] = sumMap.get(maxNegative) + countMap.get(maxNegative) * extra;
} else {
long extra = accumulatedTotal - maxPositive;
results[i] = sumMap.get(maxPositive) + (totalCount - countMap.get(maxPositive)) * extra;
}
}
return results;
}
回答2:
static int[] solution(int[] arr, int[] queries)
{
int querySum = 0;
for (int i; i < queries.length; i++) {
querySum += queries[i];
}
for (int j; j < arr.length; j++) {
arr[j] += querySum;
arr[j] = Math.abs(arr[j]);
}
return arr;
}
The complexity is O(n), additional memory consumption O(1)
来源:https://stackoverflow.com/questions/59399073/reducing-complexity-to-find-the-absolute-sum-of-an-array-elements