How to increase value of a k consecutive elements in an vector in c++? - c++

Suppose we have an vector in c++ of size 8 with elements {0, 1, 1, 0, 0, 0, 1, 1} and i want to increase the size of a specific portion of vector by one, for example, lets say the portion of vector which needs to be increase by 1 is 0 to 5, then our final result is {1, 2, 2, 1, 1, 0, 0, 1, 1}.
Is it possible to do this in constant time using standard method of vectors (like we a memset in c), without running any loop?

No... and by the way with memset you don't have a guaranteed constant-time operation either (in most implementation is just very fast but still linear in the number of elements).
If you need to do this kind of operation (addition/subtraction of a constant over a range) on a very huge vector a lot of times and you need to get the final result then you can get O(1) per update using a different algorithm:
Step 1: convert the data to its "derivative"
This mean replacing each element with the difference from previous one.
// O(n) on the size of the vector, but done only once
for (int n=v.size()-1; i>0; i--) {
v[i] -= v[i-1];
}
Step 2: do all the interval operations (each in constant time)
With this representation adding a constant to a range simply means adding it to the first element and subtracting it from the element past the ending one. In code:
// intervals contains structures with start/stop/value fields
// Operation is O(n) on the **number of intervals**, and does
// not depend on the size of them
for (auto r : intervals) {
v[r.start] += r.value;
v[r.stop+1] -= r.value;
}
Step 3: Collect the results
Finally you just need to un-do the initial processing, getting back to the normal values on each cell by integrating. In code:
// O(n) on the size of vector, but done only once
for (int i=1,n=v.size(); i<n; i++) {
v[i] += v[i-1];
}
Note that both step 1 and 3 (derivation and integration) can be done in parallel on N cores with perfect efficiency if the size is large enough, even if how this is possible may be not obvious at a first sight (it wasn't for me, at least).

Related

How to uniform spread every k values over a collection of n values with k <= n?

I've a collection of k elements. I need to spread them uniformly random into a collection of n elements, where k <= n.
So for example, with this k-collection (with k = 3):
{ 3, 5, 6 }
and give n = 7, a valid permutation result (with n = 7 elements) could be:
{ 6, 5, 6, 3, 3, 6, 5}
Notice that every item within the k-collection must be used into the permutation.
So this is not a valid result:
{ 6, 3, 6, 3, 3, 6, 6} // it lacks "5"
What's the fast way to accomplish this?
The simplest way I can think of.
Add one of each item to the array. So with your example, your initial array is [3,5,6]. This guarantees that every element is represented at least once.
Then, successively pick an element at random, and add it to the array. Do this n-3 times. (i.e. fill the array with randomly selected items from the list of elements)
Shuffle the array.
This takes O(n) to fill the array, and O(n) to shuffle it.
Let's assume you have a
std::vector<int> input;
that contains the k elements you need to spread and
std::vector<int> output;
that will be filled with n elements.
I used the following approach for a similiar problem. (Edit: Thinking about it, here is a simpler and probably faster version than the original)
First we satisfy the condition that every item from input must occurr at least once in output. Therefore we put every element from input once into output.
output.resize(n); // fill with n 0's
std::copy(input.begin(), input.end(), output.begin()); // fill k first items
Now we can fill up the remaining n - k slots with random elements from input:
std::random_device rd;
std::mt19937 rand(rd()); // get seed from random device
std::uniform_int_distribution<> dist(0, k - 1); // for random numbers in [0, k-1]
for(size_t i = k; i < n; i++) {
output[i] = input[dist(rand)];
}
At the end shuffle the whole thing, to randomize the position of the first k elements:
std::random_shuffle(output.begin(), output.end(), rand);
I hope this is what you wanted.
You can try just randomly put values to ur n-collection, then verify if it contains all k-collection values if not try again. However it's not always fast xd u can also put missing values in a random place of n-collection, but remember to verify again.
Simply make an array of the k elements, say {3,5,6} in the given example. Make a variable counter, which is zero initially. If you want to spread it over n elements, simply iterate over n elements of array with the counter incrementing as
counter=(counter+1)%k;

Vectorize a Symmetric Matrix

I would like to write a function with the following signature
VectorXd vectorize (const MatrixXd&);
which returns the contents of a symmetric matrix in VectorXd form, without repeated elements. For example,
int n = 3; // n may be much larger in practice.
MatrixXd sym(n, n);
sym << 9, 2, 3,
2, 8, 4,
3, 4, 7;
std::cout << vectorize(sym) << std::endl;
should return:
9
2
3
8
4
7
The order of elements within vec is not important, provided it is systematic. What is important for my purposes is to return the data of sym without the repeated elements, because sym is always assumed to be symmetric. That is, I want to return the elements of the upper or lower triangular "view" of sym in VectorXd form.
I have naively implemented vectorize with nested for loops, but this function may be called very often within my program (over 1 million times). My question is thus: what is the most computationally efficient way to write vectorize? I was hoping to use Eigen's triangularView, but I do not see how.
Thank you in advance.
Regarding efficiency, you could write a single for loop with column-wise (and thus vectorized) copies:
VectorXd res(mat.rows()*(mat.cols()+1)/2);
Index size = mat.rows();
Index offset = 0;
for(Index j=0; j<mat.cols(); ++j) {
res.segment(offset,size) = mat.col(j).tail(size);
offset += size;
size--;
}
In practice, I expect that the compiler already fully vectorized your nested loop, and thus speed should be roughly the same.

Improving the time complexity in priority queue in c++

In the code below, I am getting time out for larger vector length, though it is working for smaller length vector.
long priceCalculate(vector < int > a, long k) {
long price = 0;
priority_queue<int>pq(a.begin(),a.end());
while(--k>=0){
int x = pq.top();
price = price + x;
pq.pop();
pq.push(x-1);
}
return price;
}
I have an array of numbers. I have to add the maximum number to price and then decrement that number by 1. Again find the maximum number and so on. I have to repeat this process for k times.
Is there any better data structure than priority queue which has less time complexity?
Below is the code using vector sort:
struct mclass {
public: bool operator()(int x, int y) {
return (x > y);
}
}
compare;
long priceCalculate(vector < int > a, long k) {
long price = 0;
sort(a.begin(), a.end(), compare);
while (--k >= 0) {
if (a[0] > 0) {
price = price + a[0];
a[0] = a[0] - 1;
sort(a.begin(), a.end(), compare);
}
}
return price;
}
But this is also giving timeout on large input length.
The sorting code has two performance problems:
You are resorting the vector<> in every iteration. Even if your sorting algorithm is insertion sort (which would be best in this case), it still needs to touch every position in the vector before it can declare the vector<> sorted.
To make matters worse, you are sorting the values you want to work with to the front of the vector, requiring the subsequent sort() call to shift almost all elements.
Consequently, you can achieve huge speedups by
Reversing the sort order, so that you are only interacting with the end of the vector<>.
Sort only once, then update the vector<> by scanning to the right position from the end, and inserting the new value there.
You can also take a closer look at what your algorithm is doing: It only ever operates on the tail of the vector<> which has constant value, removing entries from it, and reinserting them, decremented by one, in front of it. I think you should be able to significantly simplify your algorithm with that knowledge, leading to even more significant speedups. In the end, you can remove that tail from the vector<> entirely: It's completely described by its length and its value, and all its elements can be manipulated in a single operation. Your algorithm should take no time at all once you are through optimizing it...
For the vector solution you should be able to gain performance by avoiding sort inside the loop.
After
a[0] = a[0] - 1;
you can do something like the (pseudo) code below instead of calling sort:
tmp = 0;
for j = 1 to end-1
{
if a[0] < a[j]
++tmp
else
break
}
swap a[0], a[tmp]
to place the decremented value correctly in the sorted vector, i.e. since the vector is sorted from start, you'll only need to find the first element which is less or equal to the decremented value and swap the element just before with [0]. This should be faster than sort that has to go through the whole vector.
Examples of algorithm
// Vector after decremt
9, 10, 9, 5, 3, 2
^
tmp = 1
// Vector after swap
10, 9, 9, 5, 3, 2
// Vector after decremt
9, 10, 10, 5, 3, 2
^
tmp = 2
// Vector after swap
10, 10, 9, 5, 3, 2
Performance
I compared my approach with the vector example from OP:
k = 1000
vector.size = 10000000
vector filled with random numbers in range 0..9999
compiled with g++ -O3
My approach:
real 0.83
user 0.78
sys 0.05
OPs vector approach
real 119.42
user 119.42
sys 0.04

Number of swaps in a permutation [duplicate]

This question already has answers here:
Counting the adjacent swaps required to convert one permutation into another
(6 answers)
Closed 8 years ago.
Is there an efficient algorithm (efficient in terms of big O notation) to find number of swaps to convert a permutation P into identity permutation I? The swaps do not need to be on adjacent elements, but on any elements.
So for example:
I = {0, 1, 2, 3, 4, 5}, number of swaps is 0
P = {0, 1, 5, 3, 4, 2}, number of swaps is 1 (2 and 5)
P = {4, 1, 3, 5, 0, 2}, number of swaps is 3 (2 with 5, 3 with 5, 4 with 0)
One idea is to write an algorithm like this:
int count = 0;
for(int i = 0; i < n; ++ i) {
for(; P[i] != i; ++ count) { // could be permuted multiple times
std::swap(P[P[i]], P[i]);
// look where the number at hand should be
}
}
But it is not very clear to me whether that is actually guaranteed to terminate or whether it finds a correct number of swaps. It works on the examples above. I tried generating all permutation on 5 and on 12 numbers and it always terminates on those.
This problem arises in numerical linear algebra. Some matrix decompositions use pivoting, which effectively swaps row with the greatest value for the next row to be manipulated, in order to avoid division by small numbers and improve numerical stability. Some decompositions, such as the LU decomposition can be later used to calculate matrix determinant, but the sign of the determinant of the decomposition is opposite to that of the original matrix, if the number of permutations is odd.
EDIT: I agree that this question is similar to Counting the adjacent swaps required to convert one permutation into another. But I would argue that this question is more fundamental. Converting permutation from one to another can be converted to this problem by inverting the target permutation in O(n), composing the permutations in O(n) and then finding the number of swaps from there to identity. Solving this question by explicitly representing identity as another permutation seems suboptimal. Also, the other question had, until yesterday, four answers where only a single one (by |\/|ad) was seemingly useful, but the description of the method seemed vague. Now user lizusek provided answer to my question there. I don't agree with closing this question as duplicate.
EDIT2: The proposed algorithm actually seems to be rather optimal, as pointed out in a comment by user rcgldr, see my answer to Counting the adjacent swaps required to convert one permutation into another.
I believe the key is to think of the permutation in terms of the cycle decomposition.
This expresses any permutation as a product of disjoint cycles.
Key facts are:
Swapping elements in two disjoint cycles produces one longer cycle
Swapping elements in the same cycle produces one fewer cycle
The number of permutations needed is n-c where c is the number of cycles in the decomposition
Your algorithm always swaps elements in the same cycle so will correctly count the number of swaps needed.
If desired, you can also do this in O(n) by computing the cycle decomposition and returning n minus the number of cycles found.
Computing the cycle decomposition can be done in O(n) by starting at the first node and following the permutation until you reach the start again. Mark all visited nodes, then start again at the next unvisited node.
I believe the following are true:
If S(x[0], ..., x[n-1]) is the minimum number of swaps needed to convert x to {0, 1, ..., n - 1}, then:
If x[n - 1] == n - 1, then S(x) == S(x[0],...,x[n-2]) (ie, cut off the last element)
If x[-1] != n - 1, then S(x) == S(x[0], ..., x[n-1], ..., x[i], ... x[n-2]) + 1, where x[i] == n - 1.
S({}) = 0.
This suggests a straightforward algorithm for computing S(x) that runs in O(n) time:
int num_swaps(int[] x, int n) {
if (n == 0) {
return 0;
} else if (x[n - 1] == n - 1) {
return num_swaps(x, n - 1);
} else {
int* i = std::find(x, x + n, n - 1);
std::swap(*i, x[n - 1])
return num_swaps(x, n - 1) + 1;
}
}

Randomly select index from a STL vector from truth value

I have a vector that looks like:
vector<int> A = {0, 1, 1, 0, 0, 1, 0, 1};
I'd like to select a random index from the non-zero values of A. Using this example A, I want to randomly select an element from the array {1,2,5,7}.
Currently I do this by creating another array
vector<int> b;
for(int i=0;i<A.size();i++)
if(A[i])
b.push_back(i);
Once b is created, I find the index by using this answer:
get random element from container
Is there a more STL-like (or C++11) way of doing this, perhaps one that does not create an intermediate array? In this example A is small, but in my production code this selection process is in an inner-loop and A is non-static and thousands of elements long.
A great way to do this is Reservoir Sampling.
In short, you walk your array until you find the first non-zero value, and record that index as the first possible answer you might return.
Then, you continue to walk the array. Every time you find a non-zero value, you randomly might change which new index is your possible answer, with decreasing probability.
This algorithm also works great if you need M random index values from your array.
What's great about this, is that you walk each element only one time, and you don't need a separate memory structure to record the non-zero elements. It's O(N) in speed, and O(M) in memory, in your case it's O(1) in memory, since you only want 1 random value.
On the flip side, random number generators are traditionally quite slow. So, you might want to performance test this against any other ideas people come up with here, to see if the trade-off of speed-vs-memory is worth it for you.
With a single pass through the array, you can determine how many false (or true) values there are. If you are doing this kind of thing often, you can even write a class to keep track of this for you.
Regardless, you can then pick a random number i between 0 and num_false (or num_true). Then with another pass through the array, you can return the ith false (or true) index.
We can loop through each non-zero value and assign it a random number. The index with the largest random number is the one we select.
int value = 0;
int index = 0;
while(int i = 0; i < A.size(); i++) {
if(!A[i]) continue;
auto j = rand();
if(j > value) {
index = i;
value = j;
}
}
vector<int> A = {0,1,1,0,0,1,0,1};
random_shuffle(A.begin(),A.end());
auto it = find_if(A.begin(),A.end(),[](const int elem){return elem;});