vector<int> cutTheSticks(vector<int> arr) {
vector<int> res;
vector<int>::iterator it;
int i=0, mini=0, c=arr.size();
while(c>0) {
res.push_back(c);
mini=*min_element(arr.begin(),arr.end());
for(i=0;i<arr.size();i++) {
arr[i]-=mini;
}
for(auto it=arr.begin();it!=arr.end();it++) {
i=*it;
if(i==0)
arr.erase(it);
}
c=arr.size();
}
return res;
}
I am running this piece of code in the hackerank portal and not on any system.
The way you are using erase is causing the problem in this case. In fact, you exactly don't need a complex approach like this for the problem.
You can simply sort the array in reverse order and then use pop_back() while last element is 0. It will also help to reduce complexity as then you won't need to call min_element each time. You can directly use arr.back() for the minimum element.
Logic behind my approach:
In each iteration, you are subtracting minimum element from each element. This makes number(s) having the minimum value as 0. Clearly, since the array is sorted in reverse order, these numbers will be in the end of the array. You then want to remove these elements for which pop_back is one of the best available options.
Here is sample code:
vector<int> cutTheSticks(vector<int> arr) {
vector<int> res;
sort(arr.begin(), arr.end(), greater<int>());
while (not arr.empty()) {
res.push_back(arr.size());
for (auto &&i : arr)
i -= arr.back();
while (not (arr.back() or arr.empty()))
arr.pop_back();
}
return res;
}
PS:
If you want to stick with your original algorithm then replace
for (auto it = arr.begin(); it!=arr.end(); it++) {
i = *it;
if(i == 0)
arr.erase(it);
}
with something like:
arr.erase(remove(arr.begin(), arr.end(), 0), arr.end()); // called as erase-remove idiom
or
for (auto it = arr.begin(); it!=arr.end(); /* it++ */) {
i = *it;
if(i == 0)
it = arr.erase(it);
else
++it;
}
This thread may help you: Remove elements of a vector inside the loop.
Related
can somebody help me with this function: suppose that I need to remove all even numbers from a vector using reference: can I do that? Is the push_back correct or should I use something else?
void evenRemoe(vector<int>& arr) {
for(int i = 0; i < arr.size(); i++) {
if(arr[i] % 2 != 0) {
push_back(arr[i]);
}
}
}
Using push_back adds elements so that's not going to work.
You can use std::erase_if with a functor, like a lambda or other function acting as a unary predicate, to decide what elements that should be removed.
void evenRemoe(std::vector<int>& arr) {
std::erase_if(arr, [](int i) { return i % 2 == 0; });
}
Prior to C++20 you could implement the erase–remove idiom
#include <algorithm>
void evenRemoe(std::vector<int>& arr) {
arr.erase(std::remove_if(arr.begin(), arr.end(),
[](int i) { return i % 2 == 0; }),
arr.end());
}
push_back is a method of std::vector for appending an element to the end of the vector, not removing. What you need is one of the erase methods.
However, you should be careful while erasing elements of the vector you're iterating over. Care must be taken to avoid incrementing the index when you remove the element.
The better way to do this is to use std::remove_if algorithm instead of iterating the vector yourself.
void evenRemove(vector<int>& arr) {
auto it = std::remove_if(arr.begin(), arr.end(),
[](int n) { return (n % 2) == 0; });
arr.erase(it, arr.end());
}
Despite the name, std::remove_if doesn't actually remove any elements from the vector. Instead, it moves the elements that match the predicate (in our case - all even integers) to the end of the vector and returns an iterator pointing to the first of such elements. Therefore, to actually remove the elements you need to call erase with the iterators denoting the tail of the vector that contains the even integers.
No, push_back() is not the correct thing to use. That is meant for adding values, not removing them.
Also, your code is actually looking for odd values, not even values.
You can use std::vector::erase() to remove individual values, eg:
void evenRemoe(vector<int>& arr){
for(size_t i = 0; i < arr.size();){
if (arr[i] % 2 == 0){
arr.erase(arr.begin()+i);
}else{
++i;
}
}
}
Alternatively, consider using the Erase-Remove idiom via std::remove_if() and std::vector::erase(), eg:
#include <algorithm>
void evenRemoe(vector<int>& arr){
arr.erase(
std::remove_if(arr.begin(), arr.end(),
[](int value){ return (value % 2) == 0; }
),
arr.end()
);
}
Or, in C++20, via std::erase_if(), eg:
void evenRemoe(vector<int>& arr){
std::erase_if(arr,
[](int value){ return (value % 2) == 0; }
);
}
From C++20 onwards you can use std::erase_if() , Prior to c++20 erase-remove idiom used to be the solution of this problem.
v.erase(std::remove_if(v.begin(), v.end(), is_even), v.end());
Where is_even is a functor
Remove multiple element from vector using iterator.
Just take care that when we erase using iterator,it goes invalid.
int main(){
vector<int> vec={1,2,3,4,5,6,7,8,9};
for(auto it=vec.begin();it!=vec.end();){
if(*it%2==0)
vec.erase(it);
else
it++;
}
for(auto i:vec){
cout<<i<<" ";
}
return 0;
}
output:1 3 5 7 9
2nd method
int main(){
vector<int> vec={1,2,3,4,5,6,7,8,9};
vec.erase(remove_if(vec.begin(),vec.end(),[](int i){
return i%2==0;
}),vec.end());
for(auto i:vec)
cout<<i<<" ";
return 0;
}
Is there any STL function which does this?
For vector:
4 4 5 5 6 7
The expected output should be 2,because of one 6 and 7
Would you be kind to help me count them classic if there is no STL function?
I don't think there is an algorithm for that in STL. You can copy into a multimap or use a map of frequencies as suggested, but it does extra work that's not necessary because your array happens to be sorted. Here is a simple algorithm that counts the number of singular elements i.e. elements that appear only once in a sorted sequence.
int previous = v.front();
int current_count = 0;
int total_singular = 0;
for(auto n : v) {
if(previous == n) // check if same as last iteration
current_count++; // count the elements equal to current value
else {
if(current_count == 1) // count only those that have one copy for total
total_singular++;
previous = n;
current_count = 1; // reset counter, because current changed
}
}
if(current_count == 1) // check the last number
total_singular++;
You could also use count_if with a stateful lambda, but I don't think it'll make the algorithm any simpler.
If performance and memory doesn't matter to you, use std::map (or unordered version) for this task:
size_t count(const std::vector<int>& vec){
std::map<int,unsigned int> occurenceMap;
for (auto i : vec){
occurenceMap[i]++;
}
size_t count = 0U;
for (const auto& pair : occurenceMap){
if (pair.second == 1U){
count++;
}
}
return count;
}
with templates, it can be generalize to any container type and any containee type.
Use std::unique to count the unique entries(ct_u) and then user vector count on the original one (ct_o). Difference ct_o-ct_u would give the answer.
P.S.: this will only work if the identical entries are together in the original vector. If not, you may want to sort the vector first.
Using algorithm:
std::size_t count_unique(const std::vector<int>& v)
{
std::size_t count = 0;
for (auto it = v.begin(); it != v.end(); )
{
auto it2 = std::find_if(it + 1, v.end(), [&](int e) { return e != *it; });
count += (it2 - it == 1);
it = it2;
}
return count;
}
Demo
My question is very similar to How to find an item in a std::vector? However, I want to go further, suppose the item I am searching for appears several times in the vector, and I want to obtain its positions in the vector as well. For example, the vector I have is [ 1 3 4 3 7], and the item I want to search is 3. Then the positions of the item is 1 and 3. Using the std::find function, I can only obtain its first position in the vector. Any ideas?
Just stick it in a while loop,
auto i = std::find(v.begin(), v.end(), n);
std::vector<std::size_t> result;
while(i != v.end())
{
result.push_back(std::distance(v.begin(), i));
i = std::find(i + 1, v.end(), n);
}
Use std::find successive times, and then put all the results together. Use as first of the range in which you find, the position that the previous std::find returned to you plus one.
You can use std::find multiple times:
std::vector<int> vec;
// fill the vector with numbers
std::vector<int>::iterator it = vec.begin();
while (it != vec.end())
{
it = std::find(it, vec.end(), 3);
// do something with *it
if (it != vec.end())
it++;
}
Or you can simply use std::for_each:
std::vector<int> vec;
// fill the vector with numbers
std::for_each(vec.begin(), vec.end(), [&](int i)
{
if (i == 3)
{
// do something
}
});
If you are looking for the indexes/iterators for the items, you can simply use a custom loop:
std::vector<int> vec;
// fill the vector with numbers
std::vector<int> results;
for (std::size_t i = 0; i < vec.size(); ++i)
{
if (vec[i] == 3)
{
results.push_back(i);
}
}
results will then hold all of the indexes for elements matching your criteria (in this case, ==3).
I am working on a problem where I have to create subvectors from a bigger vector. If the elements in the vector are consecutive I have to create a vector of those elements. If there are elements which are not consecutive then a vector of that single elements is created. My logic is as below
vector<int> vect;
for (int nCount=0; nCount < 3; nCount++)
vect.push_back(nCount);
vect.push_back(5);
vect.push_back(8);
vector<int>::iterator itEnd;
itEnd = std::adjacent_find (vect.begin(), vect.end(), NotConsecutive());
The functor NotConsecutiveis as below
return (int first != int second-1);
So I am expecting the std::adjacent_find will give me back the iterators such that I can create vector one{0,1,2,3}, vector two{5} and vector{8}. But I am not sure if there is any simpler way?
Edit:I forgot to mention that I have std::adjacent_find in a loop as
while(itBegin != vect.end())
{
itEnd = std::adjacent_find (vect.begin(), vect.end(), NotConsecutive());
vector<int> groupe;
if( std::distance(itBegin, itEnd) < 1)
{
groupe.assign(itBegin, itBegin+1);
}
else
{
groupe.assign(itBegin, itEnd);
}
if(boost::next(itEnd) != vect.end())
{
itBegin = ++itEnd;
}
else
{
vector<int> last_element.push_back(itEnd);
}
}
Does it make any sense?
I think this is what is being requested. It does not use adjacent_find() but manually iterates through the vector populating a vector<vector<int>> containing the extracted sub-vectors. It is pretty simple, IMO.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vect { 0, 1, 2, 3, 5, 8 };
// List of subvectors extracted from 'vect'.
// Initially populated with a single vector containing
// the first element from 'vect'.
//
std::vector<std::vector<int>> sub_vectors(1, std::vector<int>(1, vect[0]));
// Iterate over the elements of 'vect',
// skipping the first as it has already been processed.
//
std::for_each(vect.begin() + 1,
vect.end(),
[&](int i)
{
// It the current int is one more than previous
// append to current sub vector.
if (sub_vectors.back().back() == i - 1)
{
sub_vectors.back().push_back(i);
}
// Otherwise, create a new subvector contain
// a single element.
else
{
sub_vectors.push_back(std::vector<int>(1, i));
}
});
for (auto const& v: sub_vectors)
{
for (auto i: v) std::cout << i << ", ";
std::cout << std::endl;
}
}
Output:
0, 1, 2, 3,
5,
8,
See demo at http://ideone.com/ZM9ssk.
Due to the limitations of std::adjacent_find you can't use it quite the way you want to. However it can still be useful.
What you can do is to iterate over the collection, and use std::adjacent_find in a loop, with the last returned iterator (or your outer loop iterator for the first call) until it returns end. Then you will have a complete set of consecutive elements. Then continue the outer loop from where the last call to std::adjacent_find returned a non-end iterator.
Honestly, I don't find any clear disadvantage of using a simple hand-crafted loop instead of standard functions:
void split(const std::vector<int> &origin, vector<vector<int> > &result)
{
result.clear();
if(origin.empty()) return;
result.resize(1);
result[0].push_back(origin[0]);
for(size_t i = 1; i < origin.size(); ++i)
{
if(origin[i] != origin[i-1] + 1) result.push_back(vector<int>());
result.back().push_back(origin[i]);
}
}
The goal is to access the "nth" element of a vector of strings instead of the [] operator or the "at" method. From what I understand, iterators can be used to navigate through containers, but I've never used iterators before, and what I'm reading is confusing.
If anyone could give me some information on how to achieve this, I would appreciate it. Thank you.
You need to make use of the begin and end method of the vector class, which return the iterator referring to the first and the last element respectively.
using namespace std;
vector<string> myvector; // a vector of stings.
// push some strings in the vector.
myvector.push_back("a");
myvector.push_back("b");
myvector.push_back("c");
myvector.push_back("d");
vector<string>::iterator it; // declare an iterator to a vector of strings
int n = 3; // nth element to be found.
int i = 0; // counter.
// now start at from the beginning
// and keep iterating over the element till you find
// nth element...or reach the end of vector.
for(it = myvector.begin(); it != myvector.end(); it++,i++ ) {
// found nth element..print and break.
if(i == n) {
cout<< *it << endl; // prints d.
break;
}
}
// other easier ways of doing the same.
// using operator[]
cout<<myvector[n]<<endl; // prints d.
// using the at method
cout << myvector.at(n) << endl; // prints d.
In C++-11 you can do:
std::vector<int> v = {0, 1, 2, 3, 4, 5};
for (auto i : v)
{
// access by value, the type of i is int
std::cout << i << ' ';
}
std::cout << '\n';
See here for variations: https://en.cppreference.com/w/cpp/language/range-for
Typically, iterators are used to access elements of a container in linear fashion; however, with "random access iterators", it is possible to access any element in the same fashion as operator[].
To access arbitrary elements in a vector vec, you can use the following:
vec.begin() // 1st
vec.begin()+1 // 2nd
// ...
vec.begin()+(i-1) // ith
// ...
vec.begin()+(vec.size()-1) // last
The following is an example of a typical access pattern (earlier versions of C++):
int sum = 0;
using Iter = std::vector<int>::const_iterator;
for (Iter it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
The advantage of using iterator is that you can apply the same pattern with other containers:
sum = 0;
for (Iter it = lst.begin(); it!=lst.end(); ++it) {
sum += *it;
}
For this reason, it is really easy to create template code that will work the same regardless of the container type.
Another advantage of iterators is that it doesn't assume the data is resident in memory; for example, one could create a forward iterator that can read data from an input stream, or that simply generates data on the fly (e.g. a range or random number generator).
Another option using std::for_each and lambdas:
sum = 0;
std::for_each(vec.begin(), vec.end(), [&sum](int i) { sum += i; });
Since C++11 you can use auto to avoid specifying a very long, complicated type name of the iterator as seen before (or even more complex):
sum = 0;
for (auto it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
And, in addition, there is a simpler for-each variant:
sum = 0;
for (auto value : vec) {
sum += value;
}
And finally there is also std::accumulate where you have to be careful whether you are adding integer or floating point numbers.
Vector's iterators are random access iterators which means they look and feel like plain pointers.
You can access the nth element by adding n to the iterator returned from the container's begin() method, or you can use operator [].
std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();
int sixth = *(it + 5);
int third = *(2 + it);
int second = it[1];
Alternatively you can use the advance function which works with all kinds of iterators. (You'd have to consider whether you really want to perform "random access" with non-random-access iterators, since that might be an expensive thing to do.)
std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();
std::advance(it, 5);
int sixth = *it;
Here is an example of accessing the ith index of a std::vector using an std::iterator within a loop which does not require incrementing two iterators.
std::vector<std::string> strs = {"sigma" "alpha", "beta", "rho", "nova"};
int nth = 2;
std::vector<std::string>::iterator it;
for(it = strs.begin(); it != strs.end(); it++) {
int ith = it - strs.begin();
if(ith == nth) {
printf("Iterator within a for-loop: strs[%d] = %s\n", ith, (*it).c_str());
}
}
Without a for-loop
it = strs.begin() + nth;
printf("Iterator without a for-loop: strs[%d] = %s\n", nth, (*it).c_str());
and using at method:
printf("Using at position: strs[%d] = %s\n", nth, strs.at(nth).c_str());