Vector iteration with multiple conditions? - c++

Say you have the following vector of Int's:
std::vector<int> V={5,4,3,2,1,6,7,8};
I need to write some form of iteration that will push all the decreasing int's into a separate vector as well as the first increasing int.
So for V, I require {5,4,3,2,1,6}
My initial thought was to use a for-loop:
std::vector<int> Results;
for(int i=V.size(); i--;)
{
if(V[i]>V[i+1]){Results.push_back(V[i]);};
}
However its at this point I'm stuck, how can I also push back the first increasing element (in this case 6)?

You need to restructure your code. For example: break when the stop condition is reached.
std::vector<int> results;
for(int i = 0; i < v.size() - 1; ++i)
{
results.push_back(v[i]);
if(v[i] < v[i+1])
{
results.push_back(v[i+1]);
break;
}
}

bool decrease = false;
for(i = 0; i < v.size() - 1; ++i)
{
if(V[i] > V[i+1]) {
decrease = true;
results.push_back(v[i]);
} else if(decrease == true) {
break;
}
}
You can add a flag to represent if the decrease sequence started.

Related

C++ - Find sum of unique elements [duplicate]

This question already has answers here:
How to remove all instances of a duplicate from a vector<int> [duplicate]
(6 answers)
Closed 2 years ago.
I am trying to get the sum of unique elements, however I am not meeting the requirements of the given output.
//Prompted Input: [1,2,3,2]
//Expected output: 4
//Explanation: The unique elements are [1,3]
Below is my relevant code. Some things I have tried was to set j to i for the nested loop, however that changed nothing. The next step I took was to take out the first if conditional and have the code do the sum after finding the unique numbers but the output was 10. I'd be grateful if someone could give me a direction of where I'm messing up because I know I am close.
int sumOfUnique(vector<int>& nums) {
int sum = 0;
for(int i = 0; i < nums.size(); i++){
for(int j = 0; j < nums.size(); j++){
if(j == i){
sum += nums[i];
}
if(nums[i] == nums[j]){
break;
}
}
}
return sum;
}
You're close in that you have nested loops, but the content of the loops is not correct. The key is that you need to identify the unique elements, that's not something that your current code does.
Use the inner loop to identify if an element is unique and then after the inner loop add it to the sum if it is. Like this
int sumOfUnique(vector<int>& nums) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) {
// count how many times nums[i] occurs
int count = 0;
for (int j = 0; j < nums.size(); j++)
if (nums[i] == nums[j])
++count;
if (count == 1) // is nums[i] unique?
sum += nums[i]; // add it to the sum if it is
}
return sum;
}
The trick is the extra variable count to work out if a particular number is unique.
You can make this code clearer and more flexible by putting the uniqueness test into it's own function. Like this
bool isUnique(vector<int>& nums, int i) {
// count how many times nums[i] occurs
int count = 0;
for (int j = 0; j < nums.size(); j++)
if (nums[i] == nums[j])
++count;
// return true if it occurs once only
return count == 1;
}
int sumOfUnique(vector<int>& nums) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) {
if (isUnique(nums, i)) // is nums[i] unique?
sum += nums[i]; // add it to the sum if it is
}
return sum;
}
It's good to split code into different functions, with each function solving one part of the puzzle. Now (for instance) you could replace isUnique with a different function and sum values in your vector based on some different criterion.
There are more efficient solutions that this using std::set but I expect that the point of this exercise is to get you practising with loops and algorithms.
You can use std::map to create a frequency counter. After that, iterate through the map and check if a number only occurred once. If that's true, add that number to the result and afterward print out the final result.
int uniqueSum(vector<int> numbers)
{
map<int, int> frequency;
for (auto it = numbers.begin(); it!=numbers.end(); it++)
{
int value = (*it);
if (frequency.find(value) == frequency.end()) {frequency[value] = 1;}
else {frequency[value]++;}
//if value already occur in map then add 1 to its counter,
//else set its counter to 1
}
int sum = 0;
for (auto it = frequency.begin(); it!=frequency.end(); it++)
{
if (it->second == 1) {sum += it->first; }
//if the element appear just once in the vector, add it to sum, else skip it
}
return sum;
}
You can read more about map here: https://www.cplusplus.com/reference/map/map/
And also the find() function: https://www.cplusplus.com/reference/map/map/find/
Use a map to store numbers you have seen, and if they repeat, mark as not-viable.
int sumOfUnique(std::vector<int>& nums)
{
std::map<int, bool> seen;
for (auto i : nums)
{
auto it = seen.find(i);
if (it != seen.end()) // If already exists, set viability to false
{
it->second = false;
}
else { seen.insert({ i, true }); } // Does not exist, is currently viable
}
int sum = 0;
for (auto pair : seen)
{
if (pair.second) // If viable
{
sum += pair.first;
}
}
}

How to erase or change element while iterating over vector in C++?

I was in the middle of creating a simple sieve of Erathostenes function when I stumbled upon one obstacle. In to order to accomplish the highest efficiency in this task I wanted to use only a vector. Here is the current code:
vector<int> sieveOfErathostenes(int N) {
vector <int> result(N, 1);
for(int i = 2; i < sqrt(N); i++)
if(result[i] == 1)
for(int j = 2*i; j < N; j += i)
result.at(j) = 0;
// :c
return result;
}
This vector returns 1 and 0 in the proper position but I can't figure out how to implement both erasing or changing an element's value in a single loop. When I use an iterator to erase an element as in erase set element while iterating/// I can't access the vector to change its value, and when I use a standard for loop to access the element I can't remove it. I have tried going from the end of the vector and counting non zero elements and giving some offset when erasing but no success.
TL DR: What I can't figure out is:
for(int i = 0; i < N; i++)
{
if(result[i] == 0) {
//remove at position i
} else {
result.at(i) = i;
}
}
Thank you in advance for your time :)
Instead of erasing elements in the middle of the vector, you should write the results from the beginning of the vector and eliminate the unused elements in the end of vector.
int finalSize = 0;
for(int i = 0; i < N; i++)
{
if(result[i] != 0) {
result[finalSize++] = i;
}
}
result.resize(finalSize);
If you still need to remove an element from a std::vector during traversal, keep in mind that erase returns an iterator following the last removed element:
std::vector<int> result = {1,1,1,0,1,1,1};
for(auto it = result.begin(); it != result.end(); )
{
if(*it==0)
it = result.erase(it);
else
it++;
}

How to remove 'goto' from this loop?

I have a loop that looks for 3 equal cards or 3 non equal cards and erases as it finds, if it doesn't find 2 equals/non-equals for the 1st chosen element it deletes that 1st element and goes to the other and so on...
Well, I'm using goto in this code to break from inside of two for loops and keep iterating throughout while.
To me, it makes good sense to use goto in this specific situation. But, since I'm not a very experienced programmer I think there would be a better way to do it, a more efficient way.
Is there? How would that be? not using goto in this case.
unsigned int i1 = 0;
while(gameCards.size() > 2)
{
for(unsigned int i2=1; i2<gameCards.size(); i2++)
{
if(i2 == 2) continue;
if(cannotMatch(gameCards.at(i1), gameCards.at(i2)))
{
for(unsigned int i3=2; i3<gameCards.size(); i3++)
{
if(cannotMatch3(gameCards.at(i1), gameCards.at(i2), gameCards.at(i3)))
{
SetMatches++;
gameCards.erase(gameCards.begin()+i2,gameCards.begin()+i3);
goto findAnother;
}
}
} else if(canMatch(gameCards.at(i1), gameCards.at(i2)))
{
for(unsigned int i3=2; i3<gameCards.size(); i3++)
{
if(canMatch3(gameCards.at(i1), gameCards.at(i2), gameCards.at(i3)))
{
SetMatches++;
gameCards.erase(gameCards.begin()+i2,gameCards.begin()+i3);
goto findAnother;
}
}
}
}
findAnother:
gameCards.erase(gameCards.begin()+(i1++));
}
You can just set an extra bool condition to break outer for loop. You can also simplify your inner loops when you notice that they are essentially the same, just invoke different match3 functions:
while(gameCards.size() > 2)
{
auto continue_outer_loop(true);
for(unsigned int i2=1; continue_outer_loop && (i2<gameCards.size()); i2++)
{
if(i2 == 2) continue;
auto const p_match_3_func
(
cannotMatch(gameCards.at(i1), gameCards.at(i2))
?
&cannotMatch3
:
&canMatch3
);
for(unsigned int i3=2; i3<gameCards.size(); i3++)
{
if((*p_match_3_func)(gameCards.at(i1), gameCards.at(i2), gameCards.at(i3)))
{
SetMatches++;
gameCards.erase(gameCards.begin()+i2,gameCards.begin()+i3);
continue_outer_loop = false;
break;
}
}
}
gameCards.erase(gameCards.begin()+(i1++));
}
You can add guard variable and check for it in your loops. But will work, only when you do it at the end of loop as it is not real break.
while (mainLoop) {
int goMain = 0;
for (int i = 0; i < 5 && goMain == 0; i++) {
for (int j = 0; j < 5 && goMain == 0; j++) {
if (wantExit) {
goMain = 1;
}
}
}
}

Changing twice "for" loop for single "for" loop (SORTING)

This is my first post here. I have to sort values that returns True or False. My problem is that, it take too long in two loops but I can't change it to single loop.
Here is code for the sorting:
for (int i = 0; i < size; i++) {
if (f(arr[i]) == true) {
for(int j = 0; j < size; j++){
if(f(arr[j]) == false){
swap(arr[i],arr[j]);
}
}
}
And here is function:
bool isEven(int e) { return e%2 == 0; }
True vaules must be first in array and false vals on the right side(place that left). I must get rid of that inside loop. Thanks for help and advices. I can't make any new arrays, that must be done with the one in loop (arr[]).
For example for array: 1,2,3,4,5,6 -> 2 4 6 1 5 3.
The problem is that in that inner loop you start at 0 even though you know that all elements in [0, i] are false. So I think you can do this:
int i = 0;
int j = size - 1;
while (i < j) {
if (f(arr[i] == true) {
while (f[arr[j] == true && j > i) {
j -= 1;
}
swap(arr[i], arr[j]);
}
i += 1;
}
Note that while the above looks like it has 2 loops each element is examined only once so the runtime is O(n) as opposed to your original solution which is O(n^2).

Error deleting elements from a vector

I'm trying to do a method where I have to delete a number from a vector of integers, and that number is passed as a parameter. The problem that I'm having right now is that when I try to delete the same number in consecutive positions, only one of them is deleted.
For example:
vector = (1, 2, 2, 3, 4, 5) and I want to remove the number "2", the result will be:
vector = (1, 2, 3, 4, 5)
But if the number is not in consecutive positions, the method works fine:
vector = (1, 2, 3, 2, 4, 5) ---> remove "2"
vector = (1, 3, 4, 5)
The code that I have is this:
void deleteNumber(int n, vector<int> &numbers)
{
bool hasEntered = false;
int counter = 0;
vector<int> deletedNumbers;
for(unsigned i = 0; i < numbers.size(); i++)
{
if(numbers[i] != n)
{
counter++;
}
else
{
counter = 0;
int counter2 = 0;
bool deleted = false;
for(unsigned j = 0; j < deletedNumbers.size() && deleted == false; j++) // Check if a number has been deleted before
{
if(deletedNumbers[j] != n)
{
counter2++;
}
else
{
deleted = true;
counter2 = 0;
}
}
if(counter2 == (int) deletedNumbers.size()) // Remove the number if it hasn't been removed
{
deletedNumbers.push_back(n);
for(unsigned k = 0; k<numbers.size(); k++)
{
if(numbers[k] == n)
numbers.erase(numbers.begin()+k);
}
counter2 = 0;
hasEntered = true;
}
}
}
}
I think that the error could be in the condition of the last for, where I finally remove the number.
The counters are used in order to determine if an element has been found or not. And also the method has to check if the item has been removed before.
If you don't understand something, please ask me.
Thanks in advance :)
you could try something like this:
void deleteNumber(int n, vector<int> &numbers)
{
vector<int>numbers_without_n;
for(unsigned i = 0; i < numbers.size(); i++)
if(numbers[i] != n)
numbers_without_n.push_back(numbers[i]);
numbers = numbers_without_n;
}
Your code looks like too complicated, thus it can contain many bugs.
This would delete all instances of n; O(numbers.size()):
void deleteNumber(int n, vector<int> &numbers) {
int i = 0;
for (int j = 0; j < numbers.size(); ++j) {
if (numbers[j] != n) numbers[i++] = numbers[j];
}
numbers.resize(i);
}
This would delete the first instance of n in each run; O(numbers.size()):
void deleteNumber(int n, vector<int> &numbers) {
int i = 0;
for (int j = 0; j < numbers.size();) {
if (numbers[j] == n) {
for (++j; j < numbers.size() && numbers[j] == n; ++j) {
numbers[i++] = numbers[j];
}
} else {
numbers[i++] = numbers[j++];
}
}
numbers.resize(i);
}
This would delete the first instance of n; O(numbers.size()):
void deleteNumber(int n, vector<int> &numbers) {
int i = 0;
for (int j = 0; j < numbers.size(); ++j) {
if (numbers[j] == n) {
for (++j; j < numbers.size(); ++j) {
numbers[i++] = numbers[j];
}
break;
}
numbers[i++] = numbers[j];
}
numbers.resize(i);
}
Pick whichever you need.
Please note that other answers, such as luk32's answer contain simpler code (using more STL) for deleting the first instance of n.
If you want to find and fix the bug in your code, I recommend that you try to find a very short input vector for which it fails, and then single-step through it in a debugger.
You don't need to have a loop inside the loop. The easiest way to handle the delete is to delete one item at a time and realize that this will mean you don't want to increment i when you have deleted an item. The easiest way to cancel the increment of i in the for loop is to decrement it first using --i. So you loop becomes
Check if the item matches the number
If so, delete the item and decrement i
Use std::remove and vector::erase
#include <algorithm>
void deleteNumber(int n, vector<int>& numbers)
{
numbers.erase(std::remove(numbers.begin(), numbers.end(), n), numbers.end());
}
First, I'm not sure what counter and counter2 are used for - if they're just being used to determine if you've iterated to the end of the vector without finding an element, you don't need them.
For the purpose of 'check if a number has been deleted', you just need a single boolean variable at the very top of the method, i.e. not inside the scope of the for loop.
I believe the following:
if(counter2 == (int) deletedNumbers.size()) // Remove the numbers if it hasn't been removed
can be replaced with if (!deleted).
So, here's a 'fixed' version while trying to stay as close to your existing logic as possible based on your code comments. This may not be the most efficient/elegant implementation however, I believe I have seen some other answers that use algorithms from the STL library to achieve the same thing.
void deleteNumber(int n, vector<int> &numbers)
{
bool deleted = false;
for(unsigned i = 0; i < numbers.size(); i++)
{
if (numbers[i] == n) // If we've found an instance of the number we're trying to delete
{
if (!deleted) // Check if an instance has already been deleted
{
numbers.erase(numbers.begin() + i); // Remove the number
deleted = true; // Flag that we have deleted an instance of the number
}
}
}
}
Alternately, instead of using a flag for 'deleted' to prevent deleting numbers after the first instance, you could optimize by just returning after you delete the first instance - that will prevent the rest of the loop from executing.
Ok, since apparently std::vector::erase does exists I would use standard c++ features:
void deleteNumber(int n, vector<int> &numbers) {
auto it = find(std::begin(numbers), std::end(numbers), n);
if(it != numbers.end()) numbers.erase(it);
}
EDIT: Forgot that end() is not a valid argument for erase.