I have the following given vector:
vector<int> arr = {2,1,2,2,2,3,4,2};
The goal is to move a target number all the way to the back. Say target is 2, then final result should be something like:
arr = {1,3,4,2,2,2,2,2}
Attempt
My approach is to loop through the vector, then if I find a 2, I would use push_back to add to the end, and at the same time, erase the current 2.
In code, it looks like this:
vector<int> moveEndV1(vector<int> &arr, int toMove){
for (unsigned int i = 0; i < arr.size() ; i++) {
if (arr[i] == toMove) {
arr.push_back(arr[i]); // add to the end
arr.erase(arr.begin()+i); // erase current
}
}
return arr;
}
Problem Once we erase the an element, the loop counter is wrong because now it is dealing with a modified vector.
In other words, say we start with the original vector:
{2,1,2,2,2,3,4,2}
At i = 0, the value is 2 so we moved 2 to the back and erased the first 2.
So we have at i = 0:
{1,2,2,2,3,4,2,2}
This is fine, but then when we go to i = 1, the value at i = 1 is no longer 1 like the original array, but instead it is 2. This is because we erased an element when we were at i = 0. So, at i = 1, after push_back and erasing, we get:
{1,2,2,3,4,2,2,2}
So far so good, but now if we go to i = 2, we get:
{1,2,3,4,2,2,2,2}
i will keep increasing till the end, and in the end we have that extra 2 at the front.
{1,2,3,4,2,2,2,2}
Is there a way to resolve this? Other than writing a separate function to search for this 2 at the front and then move to back?
Any help is greatly appreciated.
You can do this easily by using std::stable_partition:
std::stable_partition(arr.begin(), arr.end(),
[toMove](int i) { return i != toMove; });
#cigien solution is elegant;
but modified your code a bit, will work too;
void moveEndV1(std::vector<int> &arr, int toMove){
auto it = arr.begin();
for ( int i = 0; i < arr.size(); i++ )
{
if (*it == toMove )
{
int val = *it;
it = arr.erase( it );
arr.push_back( val );
}
else
{
++it;
}
}
}
A stable partition works, but seems like an overkill (O(n log n) time, O(log n) space). Since you know your target number, you don't have to push it back immediately. Instead, use two iterators, src and dst, along the lines of
auto dst = arr.begin();
for (auto src = arr.begin(); src != arr.end(); src++) {
if (*src != toMove) {
*dst++ = *src;
}
}
// At this point all non-target numbers are at the beginning of the
// array, and the order is preserved. Fill the rest with the target.
while (dst != arr.end()) {
*dst++ = toMove;
}
Related
how can I change the code that after erasing first number, next iterator doesn't skip that number and compares it with the next one?
//previous number
auto i = aa.begin();
//next number
auto j = ++aa.begin();
while (j != aa.end()) {
if (*i < *j) {
//if next number is bigger - it gets erased
j = aa.erase(j);
continue;
}
i = j;
++j;
}
}
std::vector::erase returns an iterator to the first element after the removed elements. Hence you only need to increment the iterator when nothing has been erased:
if (*std::next(j) < *j) {
j = aa.erase(j);
} else {
++j;
}
Instead of keeping track of i manually you can use std::next to get the next iterator. In that case you need to stop the loop when std::next(j) == end.
Iterate through it backwards, and remove an element if its previous element is <= it.
You can store the value of the previous number in a variable.
//previous number
auto i = aa.begin();
//next number
auto previousValue = *i
auto j = ++aa.begin();
while (j != aa.end()) {
if (previousValue < *j) {
//if next number is bigger - it gets erased
previousValue = *j;
j = aa.erase(j);
continue;
}
i = j;
previousValue = *j;
++j;
}
}
It is best to use standard library for this kind of operations. Smaller chance to make mistake.
Also designing functions API keeping common standard from STL library is a good practice too:
template <typename It>
auto remove_smaller_then_prev(It b, It e)
{
if (b == e)
return e;
auto prev = *b++;
return std::remove_if(b, e, [&prev](const auto& x) { return x < std::exchange(prev, x); });
}
template <typename V>
void erase_smaller_then_prev(V& v)
{
auto newEnd = remove_smaller_then_prev(std::begin(v), std::end(v));
v.erase(newEnd, std::end(v));
}
https://godbolt.org/z/s96xW4qf9
Extra question: how about testcase: 5, 3, 4 what should be the result, I assumed: 5, 4.
Side note: please remember that code exists in some context, so it is a good practice to show problematic code inside a complete function which provides such context (like in my answer).
Do not keep erasing from the vector. Instead, use the read-write-pointer pattern. It performs much better and is easier to reason about.
template <typename T>
void removeUnsorted(std::vector<T>& vec) {
if (vec.empty()) return;
auto last = begin(vec);
auto write = begin(vec);
for (auto read = begin(vec); read != end(vec); ++read) {
if (!(*last < *read)) {
*write++ = *read;
}
last = read; // !
}
vec.resize(distance(begin(vec),write));
}
Basically this tracks all value you want to keep between begin(vec) and write. The read iterator goes over every value once and copies it to *write if and only if you decide to keep it.
You can decide with which value to compare, the last one read or the last one written. The code as it stands now compares against the last one read, such that this:
{7,6,9,4,3,8,5,2}
gets transformed to this:
{7,6,4,3,5,2}
^----- note the 5
If you do not want this, but want to always have a descending value, move the line with a // ! comment inside the if condition, thereby only updating the "compare-to" value when it was kept, not when it was encountered.
In the very last line, you truncate the vector, dropping every value that was not kept. Note that this is done in constant time for integers.
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
If I have a set in C++, and it contains numbers from 0 to n. I wish to find out the number that is missing from 1 to n and output that and if none of them is missing, then output the number (n+1).
For example, if the set contains, 0 1 2 3 4 5 6 7, then it should output 8
If it contains, 0 1 3 4 5 6, then it should output 2.
I made the following code for this, but it always seems to output 0. I dont know what is the problem.
set<int>::iterator i = myset.begin();
set<int>::iterator j = i++;
while (1)
{
if ( *(j) != *(i)+1 )
{
cout<<*(j)<<"\n";
break;
}
else
{
i++;
j++;
}
}
What is the problem? Thanks!
The problem is that you're advancing i:
set<int>::iterator i = myset.begin(); // <-- i points to first element
set<int>::iterator j = i++; // <-- j points to first element
// i points to second!
while (1)
{ // so if our set starts with {0, 1, ...}
if ( *(j) != *(i)+1 ) // then *j == 0, *i == 1, *i + 1 == 2, so this
// inequality holds
What you meant to do is have j be the next iterator after i:
std::set<int>::iterator i = myset.begin(), j = myset.begin();
std::advance(j, 1);
With C++11, there's also std::next():
auto i = myset.begin();
auto j = std::next(i, 1);
Or, alternatively, just reverse your construction:
std::set<int>::iterator j = myset.begin();
std::set<int>::iterator i = j++; // now i is the first element, j is the second
Or, lastly, you really only need one iterator:
int expected = 0;
for (std::set<int>::iterator it = myset.begin(); it != myset.end();
++it, ++expected)
{
if (*it != expected) {
std::cout << "Missing " << expected << std::endl;
break;
}
}
The easiest stuff: Use count() function of set to check whether an element is present in set or not.
The count() takes an integer argument: The number whose existence in the set is to be checked. If the element is present in set, count() returns a non zero value, else it returns 0.
For example:
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> s;
//I insert 0 - 4 in the set.
for(int i=0;i < 5; ++i)
s.insert(i);
//Let 10 be the 'n'.
for(int i = 0; i < 10; ++i)
{
//If i is NOT present in the set, the below condition will be true.
if (!s.count(i))
cout<<i<<" is missing!\n";
}
}
One problem is that you access beyond the end of the set if the set is
dense, which is undefined behavior. Another is that you always output
an element in the set (*j, where j is an iterator into the set);
according to your description, what you want to output is a value which
isn't in the set.
There are a couple of ways of handling this. The simplest is probably
just to maintain a variable expected, initialized with 0 and
incremented each time. Something like the following.
int
firstAvailable( std::set<int> const& allocated )
{
int expected = 0;
for ( auto current = allocated.begin(), end = allocated.end();
current != end && *current == expected;
++ current ) {
++ expected;
}
return expected;
}
If you don't want to return 0 if the list isn't empty, but starts with
some other value, initialize expected with the first element of the
set (or with whatever you want to return if the set is empty).
EDIT:
Of course, other algorithms may be better. For this sort of thing, I usually use a bit map.
The problem with your original code has already been pointed out in the other answers. You're modifying i while assigning j. You can fix this by initializing the iterators as:
set<int>::iterator i = myset.begin();
set<int>::iterator j = i;
j++;
A more elegant solution is to take advantage of the fact that the sum of all values up to n is n * (n + 1) / 2. You can calculate the sum of the actual values, and subtract it from the full sum to obtain the missing value:
int findMissing(const std::set<int>& valSet) {
int valCount = valSet.size();
int allSum = (valCount * (valCount + 1)) >> 1;
int valSum = std::accumulate(valSet.begin(), valSet.end(), 0);
return allSum - valSum;
}
The big advantage of this approach is that it does not rely on using a container where iterators provide the values in sorted order. You can use the same solution e.g. on an unsorted std::vector.
One danger to look out for when using this approach is overflow. With 32-bit ints, it will overflow with approximately 2^16 values. It might actually still work if it overflows, particularly if you use unsigned instead of int, but I did not confirm that.
There's a similar approach that uses the XOR of all values instead of the sum, which does not have the problem with overflow.
I'm having a lot of trouble with List iterators, and I asked a question previously but was not able to get the solution I was looking for.
I have a circular list, and I must replace the value of node n with node n + (step). I must then erase node n + (step). When I erase it puts the iterator to the element after the erased element. I need the iterator back at node n. How the heck can I do this because everytime I erase n + (step) I get an invalid iterator. My input is 5 and 2.
Please let me know if there is a better datastructure to do this with, if there is no way to iterate and erase from a list. I thought of using a Vector, but I would have to shift elements down and that would be costly if there are a lot of elements.
#include "roulette.h"
#include <iostream>
uint roulette(uint people, uint step)
{
std::list<uint>::iterator iterator;
for(uint i = people; i > 0; i--)
gl_myList.push_front(i);
iterator = gl_myList.begin();
while(people > 1)
{
iterator = advanceList(iterator, step - 1);
uint replaceValue = *iterator; // Node n's value
auto tempIterator = advanceList(iterator, step);
uint newValue = *tempIterator; //Node n + step value
iterator = gl_myList.erase(tempIterator);
//Makes it past the erase function ONCE.
//Puts the iterator back to the correct spot, and sets it value
while(*iterator != replaceValue)
{
advanceList(iterator, 1);
}
*iterator = newValue;
people--;
}
return *iterator;
}
advanceList
#include "roulette.h"
std::list<uint>::iterator advanceList(std::list<uint>::iterator& start, uint step)
{
for(uint i = 0; i < step; i++)
{
start++;
if(start == gl_myList.end())
{
start = gl_myList.begin();
}
}
return start;
}
You're not using the result of your erase() call correctly, nor are you checking for .end() prior to the next iteration. I'm all-but-certain the following is what you're at least attempting to do. And note, this is still brittle, as it is anything-but-ready for edge cases (like an initial empty list, a 0-step-value, etc.):
std::list<uint>::iterator advanceList(std::list<uint>::iterator& start, uint step)
{
for(uint i = 0; i < step; i++)
{
if(++start == gl_myList.end())
start = gl_myList.begin();
}
return start;
}
uint roulette(uint people, uint step)
{
std::list<uint>::iterator it;
for(uint i = people; i > 0; i--)
gl_myList.push_front(i);
it = gl_myList.begin();
while (gl_myList.size() > 1)
{
it = gl_myList.erase(advanceList(it, step - 1));
if (it == gl_myList.end())
it = gl_myList.begin();
}
return *it;
}
Let's fix a very simple bug in your code. advanceList modifies it's argument, when you call
auto tempIterator = advanceList(iterator, step);
both iterator and tempIterator are changed. Is it what you want to achieve?
Also in your advanceList if start was at the end as you entered teh function you must replace it with begin before entering loop.
You're not approaching this problem in the right way, I believe.
The best way to do what you want, is first to separate whathever has to be deleted from what has to be kept. You can do that with std::partition or std::stable_partition in header algorithm. Then you can delete a range of elements from your container easy and clean.
Example:
#include <vector>
#include <algorithm>
using namespace std;
// ...
bool differentFrom3(int n) { return n != 3; }
vector<int> v = { 1, 3, 4, 2, 1, 3, 4, 3, 7, 3, 1 };
// move all the 3's to one end of the vector
vector<int>::iterator it = stable_partition(v.begin(), v.end(), differentFrom3);
// v is now arranged in the following order:
// { 1, 4, 2, 1, 4, 7, 1, 3, 3, 3, 3 }
// ^
// +--- it
//
// and it points to the first element whose value is 3 (in this case, v[7])
// Now you can delete everything from the it to the end of the vector.
v.erase(it, v.end());
I'm using stable_partition here because it keeps the relative position between elements. If you don't care about that you can use partition instead.
I would like to find out the difference between this code:
Vertices {
int x;
int y;
};
vector<Vertices>point;
Vertices min1,max1;
i = point.begin();
min1.y = i->y;
min1.x = i->x;
max1.x = i->x;
i++;
if(i->x < min1.x)
{
min1.x = i->x;
}
else
{
max1.x = i->x;
}
and this code:
min1.y = point[0].y;
min1.x = point[0].x;
max1.x = point[0].x;
for (int i = 1; i < point.size(); i++) {
if (point[i].x < min1.x)
min1.x = point[i].x;
else
max1.x = point[i].x;
}
EDIT
I have added in why for the 2nd piece of code to iterate from the 2nd element. What I'm doing is to compare and get the largest and smallest values. What I don't get it is why do they give me 2 different set of values? Am I misunderstanding something wrong?
First difference is that you don't have a loop in first case. It treats only very first element.
Second difference is that you start from 1 when you have a 0-th element in the second case. It treats all elements except very first.
Even with iterator you has to have a loop. The difference between using and not using iterators is just a convenience. Iterators are just different interface to access elements in a vector.
The iterator std::vector<typename>::iterator itr starts at the beginning of the vector, which is by default the first value of of your std::vector<typename> myVector.
When using a array you should start off with the very first element which is [0] not [1].
And here's a short example (out of my code) of using a iterator in a for loop:
void Rep_C_F_in_Ex (std::vector<std::string> *vTestTwo)
{
std::vector<std::string> vTestOne_;
for (std::vector<std::string>::iterator itr = vTestTwo->begin(); itr != vTestTwo->end(); itr++)
{
boost::split_regex (vTestOne_, *itr, boost::regex (",") );
for (std::vector<std::string>::iterator iterate = vTestOne_.begin(); iterate != vTestOne_.end(); iterate++)
{
vTestThree.push_back (*iterate);
++iterate;
vTestFour.push_back (*iterate);
}
}
}
If you want to loop it as array, you should start from 0 instead of 1.
int i = 0;
Bettor write it as below:
for (std::vector<xxx>::iterator it = point.begin(); it != point.end; ++it)