30 Day Challenge Day 1 | Hackerrank - Array Manipulation
题述
原题见链接。
题解
根据题意,很容易想到蛮力解法如下:
Brute Force Method
// Complete the arrayManipulation function below.
long arrayManipulation(int n, vector<vector<int>> queries) {
vector<long> arr(n, 0);
long max_val = 0;
for(auto q : queries) {
int l = q[0]-1, r = q[1]-1;
for(int i = l; i <= r; ++i) {
arr[i] += q[2];
if(max_val < arr[i]) {
max_val = arr[i];
}
}
}
return max_val;
}
这道题难度级别是Hard,可想而知,应该没有那么简单。提交以后没有通过所有测试用例,原因是超时。
蛮力解法的复杂度是\(O(n^2)\)。有没有办法降低复杂度呢?
讨论版提示了一种方法,避免把区间内的所有元素都操作一遍,毕竟这里有一个特点是,每次区间内的元素都是加上同样的值。不妨只操作一次。
对上面的代码做一点修改,找到区间的开始点\(l\)和结束点\(r\)以后,只在开始位置\(l\)加上对应值,在区间结束点的下一位(如果存在的话)减去这个对应值。
arr[l] += q[2];
if(r+1 < n) arr[r+1] -= q[2];
这样一来,最后得到的数组通过区间求和操作得到最大指。这个方法叫做Prefix Sum Algorithm,还是第一次了解到。
举例来说,如果输入如下:
5 3
1 2 100
2 5 100
3 4 100
那么操作过程如下:
Original: 0 0 0 0 0
Step 1: 100 0 -100 0 0
Step 2: 100 100 -100 0 0
Step 3: 100 100 0 0 -100
那么,子区间\([0,i](i<=n)\)内求和得到的最大值是200,也就是所要求的结果。
最终通过的题解如下:
Prefix Sum Algorithm
// Complete the arrayManipulation function below.
long arrayManipulation(int n, vector<vector<int>> queries) {
vector<long> arr(n, 0);
long max_val = 0;
for(auto q : queries) {
int l = q[0]-1, r = q[1]-1;
arr[l] += q[2];
if(r+1 < n) arr[r+1] -= q[2];
}
long sum = 0;
for(int i = 0; i < n; i++) {
sum = sum + arr[i];
if(max_val < sum) max_val = sum;
}
return max_val;
}