I'm trying to improve my c++ knowledge using Edabit challenges and testing out 'new' functions. Current challenge wants us to write a function to reverse an array.
examples:
reverse([1, 2, 3, 4]) ➞ [4, 3, 2, 1]
reverse([9, 9, 2, 3, 4]) ➞ [4, 3, 2, 9, 9]
reverse([]) ➞ []
I tried to do this using reverse_iterator, but I have some odd result.
std::vector<int> reverse(std::vector<int> arr) {
std::vector<int> out;
for(std::vector<int>::reverse_iterator i = arr.rbegin(); i != arr.rend(); ++i)
{
out.push_back(arr[*i]);
}
return out;
}
The result I get is the following:
FAILED: Expected: equal to [ 4, 3, 2, 1 ]
Actual: [ 0, 4, 3, 2 ]
First it seems like it was just one off, o I added 1 with rbegin() and rend as follows:
for(std::vector<int>::reverse_iterator i = arr.rbegin() + 1; i != arr.rend() + 1; ++i)
And it seems that the first test passed, but following test seems way off:
FAILED: Expected: equal to [ 7, 6, 5 ]
Actual: [ 33, 0, 5 ]
I'm trying to understand how this reverse iterator is working, so please provide a solution and some clear explanation why the first test passed with the addition of 1 and why the second did not pass.
Try:
for(std::vector<int>::reverse_iterator i = arr.rbegin(); i != arr.rend(); ++i)
{
out.push_back(*i);
}
Iterator already gives you a value, not an index into a vector.
The expression in the subscript operator
out.push_back(arr[*i]);
^^^^^^^
does not make sense.
You mean
out.push_back( *i );
But in any case the function can be written better either like this to create a new reversed vector
#include <iostream>
#include <vector>
#include <iterator>
std::vector<int> reverse( const std::vector<int> &v )
{
std::vector<int> out;
out.reserve( v.size() );
for ( auto first = std::rbegin( v ), last = std::rend( v ); first != last; ++first )
{
out.push_back( *first );
}
return out;
}
int main()
{
std::vector<int> v = { 4, 3, 2, 1 };
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
auto reversed_v = reverse( v );
for ( const auto &item : reversed_v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
The program output is
4 3 2 1
1 2 3 4
Or like this to reverse a vector in place
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
void reverse( std::vector<int> &v )
{
if ( not v.empty() )
{
for ( auto first = std::rbegin( v ), last = std::rend( v ); first < --last; ++first )
{
std::iter_swap( first, last );
}
}
}
int main()
{
std::vector<int> v = { 4, 3, 2, 1 };
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
reverse( v );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
The program output is the same as shown above
4 3 2 1
1 2 3 4
Alternatively there are corresponding standard algorithms std::reverse_copy and std::reverse that you can use instead.
Prefer algorithms in the standard library to hand crafted loops as much as possible because:
1) they are more expressive;
2) they are likely to be more efficient.
std::reverse(std::begin(arr), std::end(arr));
Just include the 'algorithm' header to use std::reverse.
Related
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 3 years ago.
Improve this question
I dont understand why the condition of if-statement needs to be a pointer. I assumed a normal variable call will not give any complaints.
Was trying to learn about std::vector::erase from cppreference, got intrigued about the example there (https://en.cppreference.com/w/cpp/container/vector/erase)
#include <vector>
#include <iostream>
int main( )
{
std::vector<int> c{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto &i : c) {
std::cout << i << " ";
}
std::cout << '\n';
// Erase all even numbers (C++11 and later)
for (auto it = c.begin(); it != c.end(); ) {
if (*it % 2 == 0) {
it = c.erase(it); // THE LINE ABOVE THIS
} else {
++it;
}
}
for (auto &i : c) {
std::cout << i << " ";
}
std::cout << '\n';
}
Output
0 1 2 3 4 5 6 7 8 9
1 3 5 7 9
Hope anyone could share an explanation or direct me to an available resource.
In the classical loop:
auto it = c.begin() - it is an iterator. To access what it refers to you need to dereference it, which you do with *it. The * there does not mean pointer, it means dereference (technically, on iterators, it's a call to operator*).
See also https://en.cppreference.com/w/cpp/iterator
In the range based loop:
for (auto &i : c) - here you get back a reference to the element in the container directly. No iterators involved.
Ranged based for-loop: necessity of pointer variable as condition in
if-statement
I think that the confusion is that you are incorrectly considering the ordinary for-loop
for (auto it = c.begin(); it != c.end(); )
as the ranged for-loop.
In your program the range-based for loop is used only to output the vector.
for (auto &i : c) {
std::cout << i << " ";
}
Iterators behave as pointers. That is for them for example there are defined operator * and operator ++.
Consider a similar program that deals with an array. Of course you can not remove elements from an array but you can move "removed" elements to the end of the array.
Here is a demonstrative program.
#include <iostream>
int main()
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const size_t N = sizeof( a ) / sizeof( *a );
for ( const int *p = a; p != a + N; ++p )
{
std::cout << *p << ' ';
}
std::cout << '\n';
int *q = a;
for ( const int *p = a; p != a + N; ++p )
{
if ( not ( *p % 2 == 0 ) )
{
if ( p != q ) *q = *p;
++q;
}
}
for ( const int *p = a; p != q; ++p )
{
std::cout << *p << ' ';
}
std::cout << '\n';
return 0;
}
Its output is
0 1 2 3 4 5 6 7 8 9
1 3 5 7 9
As you can see in this if statement
if ( not ( *p % 2 == 0 ) )
you have to dereference the pointer to get the value pointed to by the pointer.
Now rewrite the program the following way using generic functions std::begin, std::cbegin, and std::cend.
#include <iostream>
#include <iterator>
int main()
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( auto p = std::cbegin( a ); p != std::cend( a ); ++p )
{
std::cout << *p << ' ';
}
std::cout << '\n';
auto q = std::begin( a );
for ( auto p = std::cbegin( a ); p != std::end( a ); ++p )
{
if ( not ( *p % 2 == 0 ) )
{
if ( p != q ) *q = *p;
++q;
}
}
for ( auto p = std::begin( a ); p != q; ++p )
{
std::cout << *p << ' ';
}
std::cout << '\n';
return 0;
}
Now the pointers look like iterators and nothing was changed in the if statement
if ( not ( *p % 2 == 0 ) )
What is the best way to extract and move elements that meet certain criteria from a STL container to another STL container (e.g., vector). For example:
std::vector<int> original {1, 2, 6, 7, 9, 34, 9, 7, 3}
// For example, I only need event numbers
auto criteria = [](const int a) -> bool { return a%2 == 0? }
std::vector<int> newvec = ...;
So, what I want after the operation is
original = {1, 7, 9, 9, 7, 3}
newvec = {2, 6, 34}
An elegant solution will be appreciated.
I'd go with customized erase/remove predicate, that would add the removed elements to newvec:
original.erase(std::remove_if(original.begin(), original.end(), [&](int n){
bool match = criteria(n);
if(match){
newvec.push_back(n);
}
return match;
}));
demo
You might want to consider throwing vector<T>::reserve into the mix if you know the approximate number of elements meeting your criteria.
There are no such algorithm in STL but it is short to write:
template <typename FIterator, typename OIterator, typename Pred>
FIterator splice_if( FIterator first, FIterator last, OIterator out, Pred p )
{
FIterator result = first;
for ( ; first != last; ++first ) {
if ( p( *first ) ) {
*result++ = *first;
} else {
*out++ = *first;
}
}
return result;
}
For objects of type int there is no great sense to use move iterators however in general case you can use move iterators.
Here is a demonstrative program that shows an approach to the task
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> original {1, 2, 6, 7, 9, 34, 9, 7, 3};
auto odd_value = []( int x ) { return x & 1; };
auto n = std::count_if( original.begin(), original.end(), odd_value );
std::vector<int> odd;
odd.reserve( n );
std::vector<int> even;
even.reserve( original.size() - n );
std::partition_copy( std::make_move_iterator( original.begin() ),
std::make_move_iterator( original.end() ),
std::back_inserter( odd ),
std::back_inserter( even ),
odd_value );
original = odd;
for ( int x : original ) std::cout << x << ' ';
std::cout << std::endl;
for ( int x : even ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
Its output is
1 7 9 9 7 3
2 6 34
I am writing an exercises on codility via c++. Here the question:
A non-empty zero-indexed array A consisting of N numbers is given. The
array is sorted in non-decreasing order. The absolute distinct count
of this array is the number of distinct absolute values among the
elements of the array.
For example, consider array A such that:
A[0] = -5
A[1] = -3
A[2] = -1
A[3] = 0
A[4] = 3
A[5] = 6
The absolute distinct count of this array is 5, because there are 5 distinct absolute values among the elements of this array,
namely 0, 1, 3, 5 and 6.
Write a function:
int solution(vector<int> &A);
that, given a non-empty zero-indexed array A consisting of N numbers,
returns absolute distinct count of array A.
For example, given array A such that:
A[0] = -5
A[1] = -3
A[2] = -1
A[3] = 0
A[4] = 3
A[5] = 6
the function should return 5, as explained above.
Assume that:
N is an integer within the range [1..100,000];
each element of array A
is an integer within the range [−2,147,483,648..2,147,483,647];
array
A is sorted in non-decreasing order.
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space
complexity is O(N), beyond input storage (not counting the storage
required for input arguments).
Elements of input arrays can be
modified.
I am writing down the following code, and I fail to find any problems in my code, but it just doesn't pass.
#include <algorithm>
#include <vector>
#include <cmath>
int solution(vector<int> &A) {
int N(A.size());
vector<long long> B(N,0);
int counter(1);
//int index(0);
int move1(0);
int move2(N-1);
if(N==1)
{return 1;}
if(N==0)
{return 0;}
if(N==2)
{
if(abs(A[0])==abs(A[1]))
{return 1;}
else{return 2;}
}
for (int i = 0 ; i < N ; ++i)
{
B[i]=abs((long long )A[i]);
}
while(move1<move2)
{
if(B[move1]==B[move1+1])
{move1+=1;}
else if(B[move2]==B[move2]-1)
{move2-=1;}
else if(B[move1]>B[move2])
{
counter+=1;
move1+=1;
}
else if(B[move1]<B[move2])
{
counter+=1;
move2-=1;
}
else{move1+=1;}
}
return counter;
}
Here's the link of performance, https://codility.com/demo/results/trainingUT9QAN-JMM/
There's some errors but I can't figure out its detail, if anyone could help me with my code, I will really appreciate!
Thanks!
You may want to have an iterative solution. Start from both ends and work your way inward toward 0.
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
size_t solution( const std::vector< int > & A )
{
std::vector< int >::const_iterator f( A.begin() );
std::vector< int >::const_reverse_iterator b( A.rbegin() );
size_t result = 0;
if( A.size() )
for( ; ( f != A.end() ) && ( b != A.rend() ); )
{
if( *f >= 0 )
return result + ( ( A.end() - f ) - ( b - A.rbegin() ) );
else if( *b <= 0 )
return result + ( ( A.rend() - b ) - ( f - A.begin() ) );
else if( *f == -*b )
++result, ++f, ++b;
else if( *f > -*b )
++result, ++b;
else
++result, ++f;
}
return result;
}
int main( int, char ** )
{
std::cout << solution( std::vector< int >{ -5, -3, -1, 0, 3, 6} ) << std::endl;
std::cout << solution( std::vector< int >{ -5, -3, -1, 0, 1, 3, 6} ) << std::endl;
std::cout << solution( std::vector< int >{ -5, -3, -1, 0, 2, 3, 6} ) << std::endl;
std::cout << solution( std::vector< int >{ -5, -3, -1, 3, 6} ) << std::endl;
std::cout << solution( std::vector< int >{ -5, -3, -1, 0, 3, 4, 5} ) << std::endl;
return 0;
}
100% solution with Ruby
def solution(a)
a.each_with_object({}){ |el, acc| acc[el.abs] = true }.size
end
Got 100/100 using Java 8 streams.
return (int) Arrays.stream(A).map(Math::abs)
.distinct().count();
def solution(A):
# Creates an empty hashset
s = set()
n = len(A)
res = 0
for i in range(n):
# If not present, then put it in
# hashtable and increment result
if (A[i] not in s):
s.add(A[i])
res += 1
return res
What is the most efficient algorithm to shift array elements at specified indices left and right by one position?
For example shift indices [1,3,5] of [a,b,c,d,e,f] to the left to get [b,a,d,c,f,e]
I don't want it to rotate if the new index is out of bounds, if that makes sense.
I am using C++ std::vector for array storage.
I'm interpreting your question as to swap the two adjacent entries of an array based on index. If this is wrong, then please clarify your question with an example for which this is not correct.
void swapElements(const std::vector<int>& indexes, std::vector<int>& array){
for(auto i : indexes){
if (i < 1 || i >= array.size()){
continue;
}
std::swap(array[i-1], array[i]):
}
}
I think the simplest way is to use std::swap with the element with the given index and the element that preceds it.
For the first element you can use
std::swap( v.front(), v.back() );
Here is an example
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<char> v = { 'a', 'b', 'c', 'd', 'e', 'f' };
for ( char c : v ) std::cout << c << ' ';
std::cout << std::endl;
for ( size_t i : { 1, 3, 5 } )
{
if ( i == 0 ) std::swap( v.front(), v.back() );
else if ( i < v.size() ) std::swap( v[i], v[i-1] );
}
for ( char c : v ) std::cout << c << ' ';
std::cout << std::endl;
return 0;
}
The output is
a b c d e f
b a d c f e
If you do not want to rotate the vector then you can sibstitute the if statement for the following
for ( size_t i : { 1, 3, 5 } )
{
if ( 0 < i && i < v.size() ) std::swap( v[i], v[i-1] );
}
Not sure how to phrase this the best way but I am wanting to get unique data in reverse. It'll be better if I give an example
If I have the data
0 1
0 3
0 4
1 0
1 2
1 5
3 0
how could I get rid of the data that is a reverse of itself? For example: 0 1 and 1 0 and I would like to get rid of 1 0 because I already saw 0 1. Another example: 0 3 and 3 0 and I would like to get rid of 3 0 because I already saw 0 3.
So the data would instead be this:
0 1
0 3
0 4
1 2
1 5
Here is the code I have for how the data is coming out.
int temp;
int tn;
for (int i=0; i < n-1; i++)
{
for (int j=0; j< 4; j++)
{
temp = grid[i].neighbor[j];
tn = get_neighbor(j);
cout << i << " " << grid[i].neighbor[j] <<endl; //index
}
}
Note that it is i and grid[i].neighbor[j] that are producing the two numbers.
If you may not to change the order of elements of the original vector then the straightforward approach is the following
std::vector<std::vector<int>> v;
int a[][2] = { { 0, 1 }, { 0, 3 }, { 0, 4 }, { 1, 0 }, { 1, 2 }, { 1, 5 }, { 3, 0 } };
std::transform( std::begin( a ), std::end( a ), std::back_inserter( v ),
[]( const int ( &row )[2] )
{
return std::vector<int>( std::begin( row ), std::end( row ) );
} );
for ( const std::vector<int> &row : v )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
std::cout << std::endl;
std::function<bool( const std::vector<int> &, const std::vector<int> & )> identical =
[]( const std::vector<int> &v1, const std::vector<int> &v2 )
{
return ( v1.size() == v2.size() && v1.size() == 2 &&
( v1[0] == v2[0] && v1[1] == v2[1] || v1[0] == v2[1] && v1[1] == v2[0] ) );
};
auto last = v.begin();
for ( auto first = v.begin(); first != v.end(); ++first )
{
using namespace std::placeholders;
if ( std::find_if( v.begin(), last, std::bind( identical, _1, *first ) ) == last )
{
if ( first != last ) *last = *first;
++last;
}
}
v.erase( last, v.end() );
for ( const std::vector<int> &row : v )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
Of course there was no any need to define intermediate array a that to initialize the vector. You can initialize it using initializer list.
The output is
0 1
0 3
0 4
1 0
1 2
1 5
3 0
0 1
0 3
0 4
1 2
1 5
1) Sort the dataset
2) Check for duplicates (just normally, not in reverse)
3) Remove any duplicates found
4) Loop through and check each item against the reverse of each item (two for loops)
Steps 1/2/3 can be combined into step 4 for less iteration, or they can be seperated into a set. A set in C++ will automatically remove duplicates for steps 2 and 3 as well as sort your values and is a good chance to check out some STL stuff (Standard Template Library).
I have an idea on how to implement this, just for share, please do not vote down my answer..
The key point here is how to recognize two reverse pair, of course we can compare each of them, but there are surely more elegant way to do this.
If your numbers are in some fixed range integer, for example 0..10, then you can define a prime number array like this prime_arr = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31], now we can see if two pairs <x. y> and <a, b> are the same or in reverse, we can just compare prime_arr[x] * prime_arr[y] and prime_arr[a] * prime_arr[b].
Oh, it is just a sample, if your number is not in fixed range, but all non negative integer, you can consider x^2 + y^2, if two pairs <x, y> and <a, b> are the same or in reverse, compare x^2 + y^2 and a^2 + b^2.
Here is a demo implementation, hope it is useful for you...
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<pair<int, int>> v = { { 0, 1 }, { 0, 3 }, { 0, 4 },
{ 1, 0 }, { 1, 2 }, { 1, 5 }, { 3, 0 }};
vector<int> flagv;
for (auto p : v) {
int flag = p.first * p.first + p.second * p.second;
if (find(flagv.begin(), flagv.end(), flag) == flagv.end()) {
cout << p.first << " " << p.second << endl;
flagv.push_back(flag);
}
}
return 0;
}
Just one look for scanning the pair list..
Anyway, it is an advice from me, and limited usage(non negative integer), but you can figure out more proper computation to recognize two pair whether they are in reverse or the same.
just use comparator that normalize pair:
typedef std::pair<int,int> ipair;
typedef std::vector<ipair> ipvector;
inline
ipair norm( const ipair &p )
{
return ipair{ std::min( p.first, p.second ), std::max( p.first, p.second ) };
}
struct norm_cmp {
bool operator()( const ipair &p1, const ipair &p2 )
{
return norm( p1 ) < norm( p2 );
}
};
int main()
{
ipvector v = { { 0, 1 }, { 0, 3 }, { 0, 4 },
{ 1, 0 }, { 1, 2 }, { 1, 5 }, { 3, 0 }};
std::set<ipair, norm_cmp> s( v.begin(), v.end() );
for( const ipair &p : s )
std::cout << '{' << p.first << ',' << p.second << '}' << std::endl;
}
run on ideone