Quadratic Maximum contiguous subsequence sum algorithm
int maxSubSum2( const vector<int> & a)
{
int maxSum = 0;
for (int i = 0; i< a.size(); ++i)
{
int thisSum = 0;
for (int j = i; j < a.size(); ++j)
{
thisSum += a[j];
if (thisSum > maxSum)
maxSum = thisSum;
}
}
return maxSum;
}
I was wondering if anyone can explain how the algorithm works? I am good with for loops, I'm just bad at nested ones. Is "thisSum" always 0 every time the outer for loop on line 8 runs or is it static?
Thank you very much! I am trying really hard to understand the algorithm. Please help me! I really appreciate the time and effort.
The outer loop iterates over every element of the vector a. On each iteration, i will be the index of the current element, it resets thisSum to 0, and it then executes the inner loop.
The inner loop iterates over every element starting from i. On each iteration, j will be the index of its current element. It then calculates the sum of these elements in thisSum.
The outer loop replaces maxSum with thisSum if it's higher than what it already contains.
So if the vector contains:
1 7 -10 2 4
the successive iterations of the outer loop will calculate the following values of thisSum:
1 + 7 + -10 + 2 + 4 = 4
7 + -10 + 2 + 4 = 3
-10 + 2 + 4 = -4
2 + 4 = 6
4 = 4
The first iteration it will set maxSum to 4. After the 2nd and 3rd iterations, thisSum > maxSum will be false, so it won't change it. On the 4th iteration, 6 > 4, so it will set maxSum to 6. The last iteration won't change it. Finally, it will return 6.
Every time the outer for loop loops, this sum is reset to 0 because of the =0 that is on the first line of the outer loop.
I suggest you modify your function to print i, j, and thisSum in the inner loop so that you can see how they are changing.
Example a = [1, 2, 3, 4, 5]
j starts at the value of i, so it will first start at 0, then 1, then 2 and so on. Thus this second, inner loop is smaller each time the outer loop increments.
thisSum is reset to 0 each time as it is NOT static. If it was, it would be labeled static.
Basically, in this algorithm the outer loop is used to push the 'starting index' forward, with the inner loop used to actually add all the elements of the array / vector together.
So the executions of the inner loop for the example above would be like this:
Execution 1: 1 + 2 + 3 + 4 + 5
Execution 2: 2 + 3 + 4 + 5
Execution 3: 3 + 4 + 5
Execution 4: 4 + 5
Execution 5: 5
Hope that helps.
thisSum at your code line 8 is reset at beginning part of loop i,
but thisSum in your loop j is keep adding the array a[ ] element in loop j.
Normally I will substitute value and assume value to understand how the loop work.
Let assume vector a has 3 int elements 10,-20,100
therefore a.size() = 3
//maxSum is initialized in the function
int maxSum = 0;
//Start First i loop
int i = 0; i < 3;
int thisSum = 0;
int j = i = 0; j < 3;
thisSum += a[0];
//thisSum = 10
//10 > 0
if (thisSum > maxSum) maxSum = thisSum = 10;
int j = i = 1; j < 3;
thisSum += a[1];
//thisSum = -10
// -10 not > 10
int j = i = 2; j < 3;
thisSum += a[2];
//thisSum = 90
//90 > 10
if (thisSum > maxSum) maxSum = thisSum = 90;
//End First i loop
//Start 2nd i loop
int i = 1; i < 3;
int thisSum = 0;
int j = i = 1; j < 3;
thisSum += a[1];
//thisSum = -20
//-20 not > 90
int j = i = 2; j < 3;
thisSum += a[2];
//thisSum = 80
//80 not > 90
//End 2nd i loop
//Start 3rd i loop
int i = 2; i < 3;
int thisSum = 0;
int j = i = 2; j < 3;
thisSum += a[2];
//thisSum = 100
//100 > 90
if (thisSum > maxSum) maxSum = thisSum = 100;
//End 3rd i loop
//return 100
//return maxSum
The concept of the function is it try to get the maximum sum by step by step remove the item from smallest index element to the largest index argument.
1st loop i : maxSum = 90
2nd loop i : maxSum = 90 (remove 10)
3rd loop i : maxSum = 100 (remove 10,-20)
Related
I need to find the minimum sum of the distances between an element in the array and the set of k-elements of the array, not including that index.
For example:
arr = {5, 7, 4, 9}
k = 2
min_sum(5) = |5-4| + |5-7| = 3
min_sum(7) = |7-9| + |7-5| = 4
min_sum(4) = |4-5| + |4-7| = 4
min_sum(9) = |9-7| + |9-5| = 6
So, a naive solution would be to subtract the i-th element from each element of the array, then sort the array and calculate the sum of the first k elements in the sorted array. But it takes too long... I believe this is a dp-problem or something like that (maybe treaps).
Input:
n - number of array elements
k - number of elements in a set
array
Constraints:
2 <= n <= 350 000
1 <= k < n
1 <= a[i] <= 10^9
time limit: 2 seconds
Input:
4
2
5 7 4 9
Output:
3 4 4 6
What is the most efficient way to solve this problem? How to optimize the search for the minimum sum?
This is my code in C++, and it works about 3 mins for n = 350 000, k = 150 000:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k, tp;
unsigned long long temp;
cin >> n >> k;
vector<unsigned int> org;
vector<unsigned int> a;
vector<unsigned long long> cum(n, 0);
//unordered_map <int, long long> ans;
unordered_map <int, long long> mp;
for (int i = 0; i < n; i++){
cin >> tp;
org.push_back(tp);
a.push_back(tp);
}
/*
srand(time(0));
for (int i = 0; i < n; i++){
org.push_back(rand());
a.push_back(org[i]);
}
*/
sort(a.begin(), a.end());
partial_sum(a.begin(), a.end(), cum.begin());
mp[a[0]] = cum[k] - cum[0] - a[0] * k;
//ans[a[0]] = mp[a[0]];
for (int i = 1; i <= k; i++) {
mp[a[i]] = a[i] * i - cum[i-1] + cum[k] - cum[i] - a[i] * (k-i);
}
for (int i = 1; i < n-k; i++){
for (int j = 0; j <= k; j++){
//if (ans.find(a[i+j]) != ans.end()) {continue;}
temp = ( (a[i+j] * j) - (cum[i+j-1] - cum[i-1]) ) + ( cum[i+k] - cum[i+j] - a[i+j] * (k-j) );
if (mp.find(a[i+j]) == mp.end()) { mp[a[i+j]] = temp; }
else if (mp[a[i+j]] > temp) { mp[a[i+j]] = temp; }
//else { ans[a[i+j]] = mp[a[i+j]]; }
}
}
for (int i = 0; i < n; i++) {
cout << mp[org[i]] << " ";
}
return 0;
}
We can solve this problem efficiently by taking the sliding window approach.
It seems safe to assume that there are no duplicates in the array. If it contains duplicates, then we can simply discard them with the help of HashSet.
The next step is to sort the array to guarantee that the closest k elements will be within the window [i - k; i + k] for each index i.
We will keep three variables for the window: left, right and currentSum. They will be adjusted accordingly at each iteration. Initially, left = 0 and right = k(since the element at index 0 doesn't have elements to its left) and currentSum = result for index 0.
The key consideration is that the variables left and right are unlikely to change 'significantly' during the iteration. To be more precise, at each iteration we should attempt to move the window to the right by comparing the distances nums[i + right + 1] - nums[i] vs nums[i] - nums[i - left]. (You can prove mathematically that there is no point in trying to move the window to the left.) If the former is less than the latter, we increment right and decrement left while updating currentSum at the same time.
In order to recalculate currentSum, I would suggest writing down expressions for two adjacent iterations and looking closer at the difference between them.
For instance, if
result[i] = nums[i + 1] + ... + nums[i + right] - (nums[i - 1] + ... + nums[i - left]) + (left - right) * nums[i], then
result[i] = nums[i + 2] + ... + nums[i + right] - (nums[i] + ... + nums[i - left]) + (left - right + 2) * nums[i + 1].
As we can see, these expressions are quite similar. The time complexity of this solution is O(n * log(n)). (my solution in Java for n ~ 500_000 and k ~ 400_000 works within 300 ms) I hope this together with the consideration above will help you.
Assuming that we have sorted the original array nums and computed the mapping element->its index in the sorted array(for instance, through binary search), we can proceed with finding the distances.
public long[] findMinDistances(int[] nums, int k) {
long[] result = new long[nums.length];
long currentSum = 0;
for (int i = 1; i <= k; i++) {
currentSum += nums[i];
}
result[0] = currentSum - (long) k * nums[0];
int left = 0;
int right = k;
currentSum = result[0];
for (int i = 1; i < nums.length; i++) {
int current = nums[i];
int previous = nums[i - 1];
currentSum -= (long) (left - right) * previous;
currentSum -= previous;
if (right >= 1) {
currentSum -= current;
left++;
right--;
} else {
currentSum += nums[i - 1 - left];
}
currentSum += (long) (left - right) * current;
while (i + right + 1 < nums.length && i - left >= 0 &&
nums[i + right + 1] - current < current - nums[i - left]) {
currentSum += nums[i + right + 1] - current;
currentSum -= current - nums[i - left];
right++;
left--;
}
result[i] = currentSum;
}
return result;
}
For every element e in the original array its minimal sum of distances will be result[mapping.get(e)].
I think this one is better:
Sort the array first then you can know that fact -
For every element i in the array the k minimum distances of it with other elemets will be the distances with the ones that in k places around it in the array.
(of course it's maybe to the right or to the left or from both sides).
So for every element i to calculate min_sum(a[i]) do that:
First, min_sum(a[i]) = 0.
Then, go with two indexes, let's mark them r (to the right of i) and l (to the left of i)
and compare the distance (a[i]-a[r]) with the distance (a[i]-a[l]).
You will add the smallest to min_sum(a[i]) and if it was the right one then
increas index r, and if it was the left one then decrease index l.
Of course if the left got to 0 or the right one got to n you will most take the distaces with elemets from the other side.
Anyway you do that till you sum k elemets and that's it.
This way you didn't sort any thing but the main array.
I am trying to remove every 2nd element from an integer vector in C++
int n = 10001;
std::vector<int> sieve;
for (int i = 2; i <= n; ++i)
sieve.push_back(i);
for (int i = 2; i < sieve.size(); i += 2)
sieve.erase(sieve.begin() + i);
I want to remove every 2nd element from the vector ( which would be multiples of 2 in range from 2-10001). The output is this:
// index, value
0 2
1 3
2 5
3 6
4 8
5 9
6 11
7 12
8 14
9 15
10 17
....
So it removes the 4, 10, and 16 as expected. However there are still many multiples of 2 still in there, ie 6, 8, 12, 14
EDIT Solved using method #Retired Ninja posted in comments. (Do it in reverse)
for (int i = 2; i <= n; i++)
sieve.push_back(i);
for (int i = sieve.size(); i >= p; i -= p)
sieve.erase(sieve.end() - i);
When you are erasing second element the iterator of next element decrease 1.
So increasing 1 time of loop variable is ok.
int n = 100;
std::vector<int> sieve;
for (int i = 2; i <= n; ++i)
sieve.push_back(i);
for (int i = 2; i < sieve.size(); i += 1)
sieve.erase(sieve.begin() + i);
And another way in case of erasing pth element:
int cnt=0;
int l=sieve.size();
for (int i = 2; i < l; i += p){
sieve.erase(sieve.begin() + (i-cnt));
cnt++;
}
How about this? This removes every nth element starting at start from vec.
It's performed in-place, involves only a single array resize, and each element not erased is moved exactly once.
void remove(std::size_t nth, std::size_t start, std::vector<int> &vec)
{
std::size_t step;
for (step = 1; start < vec.size(); ++step, start += nth)
{
for (std::size_t i = 1; i < nth && start + i < vec.size(); ++i)
{
vec[start + i - step] = vec[start + i];
}
}
vec.resize(vec.size() - (step - 1));
}
I am trying to solve the following problem. Let's say I have a symmetric matrix with size n. I want to take all the "important values", and store them into a vector. Let me give an example to explain it better.
Let's say I have the following matrix A = [1, 2, 3 // 2, 5, 6 // 3, 6, 9]. I want to define vector of size n*(n+1)/2 such that:
V = [A(0,0), A(0,1), A(0,2), A(1,1), A(1,2), A(2,2) ]
I want to find a function that receives as input two integer i and j, and outputs the corresponding value of the matrix. The catch is that I do not want to access the matrix directly, instead I want to access the vector.
This is my reasoning so far. If I have an input with j < i, I just swap them since the matrix is symmetric. If I have that i == 0, the position in the array is just j. If that is not the case, I think I need to do something like this. (n is the dimension of the matrix, and position is the integer that I need when for the array.)
int position = 0;
for(int k = 0; k < i; k++){
position = position + (n-k);
}
position = position + j % i;
However, this code fails. I think I'm close to the solution but I am missing something. Any help?
The last j % i should be j - i.
In addition, the loop is essentially doing
position = n + (n - 1) + ... + (n - i + 1);
which can be simplified to
position = (n * 2 - i + 1) * i / 2;
So you can simply write
position = (n * 2 - i + 1) * i / 2 + j - i;
or
position = (n * 2 - i - 1) * i / 2 + j;
You can do simply this:
int myvector[matrix.size()];
int pos = 0;
for(int i = 0; i < matrix.size(); i++){
for(int j = 0; j < matrix.size(); j++){
if(j > i) myvector[pos++] = matrix[i][j];
else myvector[pos++] = matrix[j][i];
}
}
Similar to this question: Turn while loop into math equation?, I have the following nested loop that I am trying to convert into a math equation as I need to write this up in a format that doesn't look like code. I believe I am going to need some type of summation equation.
Here is the code:
int num = 0;
for (int i = nr - 1; i >= 0; i--) {
for (int j = nc - 1; j >= 0; j--) {
ela[i][j] = num;
eha[i][j] = num + ea[i][j] - 1;
num += ea[i][j];
}
}
I know that summations start from a lower bound and continue to a higher bound, so I'm not quite sure how to apply a summation here since I start from a higher index and continue to a lower index.
I'm not sure why I'm getting downvoted, as the question I referenced is very similar to mine, has the same tags and is upvoted 14 times. Please comment below if I can improve my question somehow.
Update:
I was able to update the formula as follows:
nr = 50;
nc = 10;
num = sum[ea[i,j],i=0,nr-1,j=0,nc-1]; // correct based upon nr, nc and ea
for (int i = 0; i < nr; i) {
for (int j = 0; j < nc; j++) {
num = num - ea[i,j];
ela[i][j] = num;
eha[i][j] = num + ea[i,j] - 1;
}
}
If I am right, you can transcribe the effect as
You can describe this as the matrix ela being a 2D suffix sum of the matrix ea (for every element, sum of the elements that follow in the lexicographical ordering), while eha is the sum of matrices ela and ea minus all ones.
If the problem is just with how to express the sum when you're looping the other direction, you can change your code to:
int num = 0;
for (int i = 0; i < nr; i++) {
for (int j = 0; j < nc; j++) {
ela[nr - i][nc - j] = num;
eha[nr - i][nc - i] = num + ea[nr - i][nc - j] - 1;
num += ea[nr - i][nc - j];
}
}
I'm not saying you have to change your code to this, but from here it should be more obvious how to change this to use summation notation.
It's hard to tell without any context, but the code in question becomes more intelligible if you think of the arrays as vectors enumerating the elements in reverse order, row-major. The code below is functionally equivalent to the original one posted, but arguably easier to follow.
// n.b. ela[nr - 1 - i][nc - 1 - j] == rela(nc * i + j);
int &rela(int k) { return ela[nr - 1 - k / nc][nc - 1 - k % nc]; }
int &reha(int k) { return elh[nr - 1 - k / nc][nc - 1 - k % nc]; }
int &rea(int k) { return ea[nr - 1 - k / nc][nc - 1 - k % nc]; }
for (int k = 0, sum = 0; k < nr * nc - 1; k++) {
rela(k) = sum;
sum += rea(k);
reha(k) = sum - 1;
}
In plain English, rela(k) is the partial sum of rea elements 0 ... k-1 and reha(k) is one less than the partial sum of rea elements 0 ... k (also, rela(k) == reha(k - 1) + 1 for k > 0).
Technically, this description could be translated back in terms of the 2d arrays, but it becomes rather messy quickly.
Suppose I have a 4 by 4 matrixes like this:
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
User enters a random portion number,for the sake of simplicity let it be 2.
I want to create 2x2 matrixes inside of the big matrix.
Submatrice1:
1 1
2 2
Submatrice2:
3 3
4 4
Submatrice3:
1 1
2 2
Submatrice3:
3 3
4 4
And then i want to replace
every number in submatrice 1 with a
every number in matrice 2 with b
every number in matrice 3 with
every number in matrice 4 with d
Last form of matrix:
a a c c
a a c c
b b d d
b b d d
And this should be generalized for n*m case.
I've no idea about where to begin.I'd appericate any ideas.
I'd go with an index-based calculation, as it seems the initial content doesn't matter.
/* Input: matrix and the size (2 in the example) */
/* The number of blocks. */
int block_height = (matrix.length + size/2) / size;
for(int row = 0; row < matrix.length; row++) {
for(int col = 0; col < matrix[0].length; col++) {
int block_row = row / size;
int block_col = col / size;
/* If we count up -> down, right -> left */
char block_index = block_col * block_height + block_row;
matrix[row][col] = 'a' + block_index;
}
}
This will start placing non-alfabet characters once the alfabet runs out, though.
It should do the following for 2, I don't really know if this side case if what you thought of.
[ 1 1 1 1 1 ] [ a a d d g ]
[ 2 2 2 2 2 ] [ a a d d g ]
[ 3 3 3 3 3 ] --> [ b b e e h ]
[ 4 4 4 4 4 ] [ b b e e h ]
[ 5 5 5 5 5 ] [ c c f f i ]
I would do it like this:
someArray[4] = your input.
someBigArray[n][m];
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(i < n/2)
if(j < m/2)
someBigArray[n][m] = (char)(someArray[0] + offsetASCIIToA)
else
someBigArray[n][m] = (char)(someArray[1] + offsetASCIIToA)
else
if(j < m/2)
someBigArray[n][m] = (char)(someArray[2] + offsetASCIIToA)
else
someBigArray[n][m] = (char)(someArray[3] + offsetASCIIToA)
}
}
This is a pseduo code solution. You can adjust it for boundary cases and what not. I would just let integer division decide your border cases, this makes the most sense and is easiest, but you can modify the logic in minor ways to make it behave like you want. You could also include the logic in multiple for loops, using combinations if i = n/2, j = m/2, i < m/2 so on and so fourth. This is mildly more performant(less branching), but a bit more code. Each solution is O(m * n). The solution below outlines this possible logic.
for(int i = 0; i < n/2; i++)
for(int j = 0; j < m/2; j++)
someBigArray[n][m] = (char)(someArray[0] + offsetASCIIToA)
for(int i = n/2; i < n; i++)
for(int j = 0; j < m/2; j++)
someBigArray[n][m] = (char)(someArray[1] + offsetASCIIToA)
for(int i = 0; i < n/2; i++)
for(int j = m/2; j < m; j++)
someBigArray[n][m] = (char)(someArray[2] + offsetASCIIToA)
for(int i = n/2; i < n; i++)
for(int j = m/2; j < m; j++)
someBigArray[n][m] = (char)(someArray[3] + offsetASCIIToA)
All you have to do now is figure out your conversion of values in someArray to their appropriate character value. Just look up ASCII tables for this information, and use casting.
NOTE: this is making some assumptions about your problem. Your example, I feel, may be particularly poor. How you modify this for if your array is potentially 5 values could be defined too many ways for me to provide insight into how I would solve it.