Range updation of values in c++ vectors [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Given a vector of integers v, whose size is n and stores all 0's initially. If I want to update some elements of a range, say from index l to r, where (0<=l<r<n). Is there any efficient way instead of running loop from l to r?
For example,
v = {0,0,0,0,0,0,0}.
I want to update elements from l=2 to r=5.
Update refers to v[i] += k, where k is some known value. If k=1, then final updated vector in above case would be-
v = {0,0,1,1,1,1,0}.
Thanks:)

You can use for_each (ccpreference.com) or for_each_n
std::vector<int> data{0, 0, 0, 0, 0, 0, 0, 0};
std::for_each(data.begin() + 2, data.begin() + 6, [](int& i) { i += 1;});
// or with for_each_n
// std::for_each_n(data.begin() + 2, 4, [](int& i) { i += 1;});
for (const auto i : data) {
std::cout << i << ' ';
}
But as the comment above mentioned there will be a for loop in there, even though you don't explicitly write one.
Here a short explanation what the code does:
From the reference page we learn:
Applies the given function object f to the result of dereferencing every iterator in the range [first, last), in order.
In our case we provide for first data.begin() + 2 which is the 3rd element of the vector and for last we provide data.begin() + 6. This element is not included in the application of the function (this is what [first, last) means).
The last part is the function f that we have to provide. Here we use a lambda function that simply increases the parameter by 1. It's important that the function paramter of the lambda takes a reference (int& i) and not just a copy, otherwise the vector remain the same as we only change copies of the elements.

Related

Why sort(rbegin(), rend()) sort the structure on descending order? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
for example the code bellow sort the vec on desc order :
std::vector<int> vec = {1, 2, 5, 4, 3};
sort(vec.rbegin(), vec.rend());
for(const auto v : vec)
std::cout << v << "\n";
output 5 4 3 2 1
On the C++ reference:
Sorts the elements in the range [first,last) into ascending order. The elements are compared using operator< for the first version [...]
The function call indeed sorts the vector in the ascending order starting form the last element up to the first element because there are used reverse iterators
sort(vec.rbegin(), vec.rend());
When you are using reverse iterators then the vector is traversed in the reverse order.
Consider this for loop
for (auto first = vec.rbegin(), last = vec.rend(); first != last; ++first)
{
std::cout << *first << ' ';
}
std::cout << '\n';
Its output is
3 4 5 2 1
If you want to sort the vector in the ascending order in the direct direction then do not use the reverse iterators. For example
sort(vec.begin(), vec.end());
Or if to use the reverse iterators then instead of the default function object of the type std::less<int> you need to use a function object of the type std::greater<int>
sort( vec.rbegin(), vec.rend(), std::greater<int>() );

How to iterate over unique elements in an array in c++ [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Suppose I have the following array:
int arr[7] = {18,16,5,5,18,16,4}
How can I iterate over unique elements(18, 16, 5 and 4) in a loop in the same order in which they occur?
I could use a set but then the order of the iteration would change(set stores elements in ascending order).
What is the fastest solution to this problem?
Iterate over the array and store the numbers you have already seen in a set. For each iteration you check whether the number is already in the set or not. If yes, skip the current element. If not, process it and insert it into the set.
Also note that you want an std::unordered_set and not a std::set which is ordered. Order doesn't matter for your filtering set.
If the values are in a known limited range, you can use a lookup table. Create an array with bool elements, sized to maximum value + 1. Use the values of the first array as index into the bool array.
#include <iostream>
int main() {
int arr[7] = {18,16,5,5,18,16,4};
constexpr int maxValue = 18;
bool lookup[maxValue + 1]{};
for( auto i : arr )
{
if( ! lookup[ i ] )
{
std::cout << i << ' ';
lookup[ i ] = true;
}
}
}
Live Demo
A std::bitset would be more space efficient but also slower, because individual bits cannot be directly addressed by the CPU.
Simply replace the bool array like so:
std::bitset<maxValue + 1> lookup;
The remaining code stays the same.
Live Demo

Group duplicate items in vector - c++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
INPUT : [3,3,3,2,2,2,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0]
OUTPUT : [[3,3,3],[2,2,2],[1,1,1,1,1],[0,0,0,0,0,0,0,0,0,0]]
The Input is a vector of int while the Output is a vector of vectors of ints. The aim is to do this in the most efficient possible way in terms of time-taken.
The solution I am currently using is this :
vector<vector<int> results;
vector<int> result;
for(int i = 0 ; i < list.size() - 1 ; i++ ){
result.push_back(list[i]);
if ( list[i] != list[i+1]){
results.push_back(result);
result.clear();
}
}
result.push_back(list[list.size()-1]);
results.push_back(result);
credit to : #kabanus
You should use the standard algorithm library as much as possible
This is a possible implementation:
template <class T>
auto make_clusters(std::vector<T>& v) -> std::vector<std::vector<T>>
{
std::vector<std::vector<T>> clusters;
auto cluster_begin = v.begin();
while (cluster_begin != v.end())
{
auto elem = *cluster_begin;
auto cluster_end = std::find_if(cluster_begin, v.end(),
[&](int e) { return e != elem; });
clusters.emplace_back(std::distance(cluster_begin, cluster_end), elem);
cluster_begin = cluster_end;
}
return clusters;
}
You're close. You already figured out your bounds problem, but consider what happens at the interface of clusters:
..2,2,3,3...
^ ^
i i+1
You are going to enter the else (else if is unnecessary if the condition is the exact opposite of the original if) and forget to add that last 2. If there are no duplicates in the vector, such as
`{1,2,3,4}`
You are not going to add anything but empty clusters! So, you always want to add the number, rather you're in a cluster or ending it. If you're ending a cluster you also want to add it and clear.
for(int i = 0 ; i < sorted.size()-1 ; i++ ){
cluster.push_back(sorted[i]);
if ( sorted[i] != sorted[i+1]){
clusters.push_back(cluster);
cluster.clear();
}
}
Finally, as #tobi303 mentioned the last element is missing. This is especially obvious with a list with a single element ({3}). Note the last cluster is not added in any case, whether if it's a new single element at the end or just a final cluster.
So, once we exit the for we need one more check (not really) - if the cluster is empty that means the last element is not a part of it, and is a new one. Otherwise, the last cluster wasn't added yet and you need to append the last element to it, and then add the cluster. I'm leaving this one up to you.

sum values in a range of indices with O(1) complexity [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
We are given a integer vector(V[]) and two index values, A and B. We need to sum all the integers between V[A] and V[B].
For example,
V[] == {0, 1, 2, 0, 4, 0, 3}, A == 2, B == 6
Sum == V[3] + V[4] + V[5] == 4
Is it possible to solve with O(1) complexity?
I thought about using memory address operations, but I'm still not sure how it would work(something like: sum the next (B-A) addresses values from &V[A])
If preprocessing is allowed, this can be done with a secondary array.
Each element of the second array would contain the sum of the corresponding element and all preceeding elements. This one-time preprocessing is O(n) time and O(n) space.
For example:
int Vsum[7];
Vsum[0] = V[0];
for (int i=1; i<7; i++) {
Vsum[i] = Vsum[i-1] + V[i];
}
So with your given array, the corresponding summation array Vsum would contain:
{0, 1, 3, 3, 7, 7, 10}
Once you have this, you only need to perform 2 lookups: one for the upper bound and one for the lower bound. So after preprocessing, getting the range sum is O(1) every time it is performed.
For the example of A==2 and B==6, you would then calculate Vsum[B-1] - Vsum[A] == 7 - 3 == 4
O(1) Space: no problem. But O(n) time will always be required for "random" numbers.

How to get sorted elements from an starting index to a ending index in an array? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
Given an array of t integers we need to answer x queries.Each query describes an starting index and a ending index ,we need to print the sorted elements in the sub-array.
For Example-
Array={16,9,10,19,2}
for query 1 3 ,the answer would be
9 10 16
for query 2 5,the answer would be
2 9 10 19
Please suggest an optimal solution?Are there any advanced data structures involved?
The number of elements can be upto 10^5 .
Tag each element with it's position:
16 1, 9 2, 10 3, 19 4, 2 5
Sort it:
2 5, 9 2, 10 3, 16 1, 19 4
For each query walk through the result and return the elements which are within the range.
After preprocessing each query takes O(N) work.
Are there any advanced data structures involved?
Nope, not at all. First you obtain the range given by those indexes, then you sort the resulting range. Then you print it. Seems pretty simple!
In fact, it's so simple, I'm going to show you an example:
#include <algorithm>
#include <vector>
#include <iostream>
#include <cassert>
template <typename T, size_t N>
size_t len(T (&)[N])
{
return N;
}
int main()
{
int array[] = {16,9,10,19,2};
const int START = 1; // user input ( 1-based index,)
const int END = 3; // user input (inclusive range)
assert((START-1) >= 0 && (START <= len(array)));
assert((END-1) >= 0 && (END <= len(array)));
// These two lines do the work.
// Everything else is just exposition.
//
// First construct a vector from the requested subrange,
// then sort that resulting vector.
//
std::vector<int> v(array+(START-1), array+END);
std::sort(std::begin(v), std::end(v));
// Output the results to console for demo.
// Uses C++ ranged-for syntax; replace with more
// verbose equivalent if required, or do something
// else with `v`.
//
for (auto elm : v) {
std::cout << elm << ' ';
}
}
// Output: 9 10 6
Live demo
You could make the code even terser (and possibly more efficient) by copying the subrange into an std::set rather than a std::vector, so sorting happens during insertion rather than after-the-fact. I hardly think either is ever going to be as much as O(n^2), contrary to your claims.
Can you do sufficient preprocessing to share information between individual queries and get your complexity down still further? I don't know. I don't think so.
If I understood your question: Sort it.
You can use any sorting algorithm you want, Wikipedia lists a few.
Depending on which algorithm you choose, you may need extra memory / data structures.
If sorting should come later, copy the array and sort the copy. Makes more sense, than sorting over and over again for every query.