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
Related
I was attempting to solve this question on some website where you have the find the kth smallest value in c++ so I came up with:
#include <bits/stdc++.h>
using namespace std;
int kthSmallest(int arr[], int l, int r, int k) {
// l is the first index
// r is the index of the last element (size - 1)
// k is the kth smallest value
set<int> s(arr, arr + r);
set<int>:: iterator itr = s.begin();
advance(itr, (k - 1));
return *itr;
}
int main() {
int arr[] = {7, 10, 4, 20, 15};
cout << kthSmallest(arr, 0, 4, 4);
return 0;
}
This shows the output of 20 instead of 15 which is the right answer and I cannot figure out what I did wrong here.
The 2nd argument of the constructor of std::set should be an iterator for an element next to the last element, not one for the last element.
Therefore, you are operating with a set whose members are {7, 10, 4, 20}.
The line
set<int> s(arr, arr + r);
should be
set<int> s(arr, arr + r + 1);
or (to match the comment)
set<int> s(arr + l, arr + r + 1);
The range in this statement
set<int> s(arr, arr + r);
is specified incorrectly when r is equal to 4 for this array
int arr[] = {7, 10, 4, 20, 15};
that has 5 elements. It means that 15 is not present in the range [7, 10, 4, 20]. You have to specify the parameter r equal to 5 that is to the number of elements in the array instead of 4.
Also the parameter l is not used in the function.
And you need to check whether the value of k is not greater than the value of r calling the function std::advance.
Also pay attention to that the array can have duplicated values. In this case the function can return an incorrect value.
So in general your function is incorrect and unsafe.
Instead of returning an object of the type int you should return either an iterator that points to the target object in the array or to the end of the range or the index of the target element..
With your approach you should use std::multiset instead of std::set. And the value of k should start from 0 as all indices in C++. Otherwise calling the function with the value of k equal to 0 you will get undefined behavior.
Here is a demonstration program.
#include <iostream>
#include <functional>
#include <set>
#include <iterator>
size_t kthSmallest( const int arr[], size_t n, size_t k )
{
if ( not ( k < n ) ) return n;
std::multiset<std::reference_wrapper<const int>> s;
for ( size_t i = 0; i < n; i++ )
{
s.insert( std::ref( arr[i]) );
}
auto it = std::next( std::begin( s ), k );
size_t result = std::distance( arr, &it->get() );
return result;
}
int main()
{
int arr[] = {7, 10, 4, 20, 15};
const size_t N = sizeof( arr ) / sizeof( *arr );
for ( size_t i = 0; i < N; i++ )
{
std::cout << i << ": " << arr[kthSmallest( arr, N, i )] << '\n';
}
return 0;
}
The program output is
0: 4
1: 7
2: 10
3: 15
4: 20
int arr[] = {10, 20, 20, 10, 10, 30, 50, 10, 20};
I want to compare each element in an array so that I can make pairs of similar numbers using C/C++.
In above example there are three pairs (10-10, 20-20, 10-10).
I want to find number of pairs in given array(i.e. 3).
Can anyone please help me with logic?
The approach using C can differ from the approach using C++ because for example in C++ you can use standard containers and algorithms while in C they are absent.
So I will show a solution that can be implemented in the both languages.
Here you are. The program is written using C but it is easy can be transformed in a C++ program by substituting the header and only one statement: the output statement.
#include <stdio.h>
int main( void )
{
int a[] = { 10, 20, 20, 10, 10, 30, 50, 10, 20 };
const size_t N = sizeof( a ) / sizeof( *a );
size_t total = 0;
for ( size_t i = 1; i < N; i++ )
{
size_t count = 1;
for ( size_t j = 0; j < i; j++ )
{
if ( a[i] == a[j] ) ++count;
}
if ( count % 2 == 0 ) ++total;
}
printf( "The number of pairs of equal elements is %zu\n", total );
return 0;
}
The program output is
The number of pairs of equal elements is 3
In C++ you can use for example the following alternative approach using the standard container std::map or std::unordered_map.
#include <iostream>
#include <map>
int main()
{
int a[] = { 10, 20, 20, 10, 10, 30, 50, 10, 20 };
size_t total = 0;
std::map<int, size_t> m;
for ( const auto &item : a ) ++m[item];
for ( const auto &item : m ) total += item.second / 2;
std::cout << "The number of pairs of equal elements is " << total << '\n';
return 0;
}
The program output is the same as shown above.
The number of pairs of equal elements is 3
And here the C++ solution.
Same approach as Vlad. Simply count the groups of all values and divide this counter by 2, because we are lokking for pairs.
Then count the overall counts:
#include <iostream>
#include <map>
#include <algorithm>
#include <numeric>
int main() {
// The data
int arr[] = { 10, 20, 20, 10, 10, 30, 50, 10, 20 };
// The counter for occurences of one value in the array
std::map<int, size_t> counter{};
// Do Count
for (int i : arr) counter[i]++;
// Devide all counts by 2. Thats, because we are looking for pairs
std::for_each(counter.begin(), counter.end(), [](auto& p) { p.second /= 2;});
// Calculate the overall sum
size_t pairCounter = std::accumulate(counter.begin(), counter.end(), 0U,
[](const size_t v, const auto& p) { return v + p.second; });
std::cout << "\nNumber of pairs: " << pairCounter << "\n";
return 0;
}
The criterion is that at most one empty object is allowed and each object can be repeated only once.
Here's my attempt so far.
Suppose that n = 3, k = 3. Let 0 denote as an empty object.
Some possible examples:
011 101 110 112
012 102 120 113
013 103 130 121
... ... ... ...
033 303 330 332
So, I create a "pool" of { 0, 1, 1, 2, 2, 3, 3 }. Three objects will be selected from the pool, by using a permutation of logical vector
(ex. a logical vector { 0, 1, 0, 0, 0, 1, 1 } chooses 1, 3, 3 from the pool)
Then all the permutations of the three selected objects are added to the set.
However... there will be some repetition, since { 0, 1, 0, 0, 0, 1, 1 } is considered equivalent to { 0, 0, 1, 0, 0, 1, 1, } as both will choose 1, 3, 3 from the pool.
This code becomes pretty computationally expensive for higher n and k, such as when n = 8 and k = 6. Is there a more effective way to do this?
My C++ code:
set< vector<int> > generate_kperms ( int n, int k )
{
set< vector<int> > kperms;
// create vector of integers { 0, 1, 1, 2, 2, ..., n, n }
vector<int> pool( 2*n + 1 );
pool[0] = 0;
for ( int i = 1; i <= n; ++i )
pool[2*i-1] = pool[2*i] = i;
// create logical vector with k true values, to be permuted
vector<bool> logical( pool.size() );
fill( logical.end()-k, logical.end(), true );
do {
vector<int> kperm( k );
vector<int>::iterator itr = kperm.begin();
for ( int idx = 0; idx < (int) pool.size(); ++idx ) {
if ( logical[idx] )
*(itr++) = pool[idx];
}
do {
kperms.insert( kperm );
} while ( next_permutation ( kperm.begin(), kperm.end() ) );
} while ( next_permutation( logical.begin(), logical.end() ) );
return kperms;
} /* ----- end of function generate_kperms ----- */
Observe that if you generate all permutations of pool, then the length-k prefixes are almost what you want, just with a large number of consecutive duplicates. An easy but decent way to generate all of the k-permutations is to skip the duplicates by sorting the n - k suffix to be descending before calling next_permutation. To wit,
#include <iostream>
#include <set>
#include <vector>
using std::cout;
using std::greater;
using std::sort;
using std::vector;
vector<vector<int>> generate_kperms(int n, int k) {
vector<vector<int>> kperms;
vector<int> pool(2 * n + 1);
pool[0] = 0;
for (int i = 1; i <= n; ++i) {
pool[2 * i - 1] = pool[2 * i] = i;
}
do {
kperms.push_back(vector<int>(pool.begin(), pool.begin() + k));
sort(pool.begin() + k, pool.end(), greater<int>());
} while (next_permutation(pool.begin(), pool.end()));
return kperms;
}
int main() {
for (const vector<int> &kperm : generate_kperms(8, 6)) {
for (int x : kperm) {
cout << x << ' ';
}
cout << '\n';
}
}
You might be able to get more speed by implementing your own version of next_permutation that treats the n - k suffix as reverse sorted, but I can't seem to find it in Knuth 4A right now.
I'm writing an operation to find the lowest missing element of a vector, V = 1..N + 1. This has to be performed in O(N) time complexity.
Solution One:
std::vector<int> A {3,4,1,4,6,7};
int main()
{
int max_el = *std::max_element(A.begin(), A.end()); //Find max element
std::vector<int> V(max_el);
std::iota(V.begin(), V.end(), 1) //Populate V with all int's up to max element
for(unsigned into i {0}; i < A.size(); i++)
{
int index = A[i] - 1;
if(A[i] == V[index]) //Search V in O(1)
{
V[index] = max_el; //Set each to max_el, leaving the missing int
}
}
return *std::min_element(V.begin(), V.end()); //Find missing int as its the lowest (hasn't been set to max_el)
}
//Output: 2
This works completely fine.
However, I'm now trying to get this to work with vector containing negative int's.
Solution Two:
My logic is to take the same approach, however 'weight' the indexes given the size of the vector and the number of negative int's in the vector:
std::vector<int> A {-1, -4, -2, 0, 3, 2, 1}
int main()
{
int max_el = *std::max_element(A.begin(), A.end());
int min_el = *std::min_element(A.begin(), A.end());
int min_el_abs = abs(min_el); //Convert min element to absolute
int total = min_el_abs + max_el;
std::vector<int> V(total + 1);
std::iota(V.begin(), V.end(), min_el);
int index;
//Find amount of negative int's
int first_pos;
for(unsigned int i {0}; i < A.size(); i++)
{
if(A[i] >= 0) {first_pos = i; break;}
}
for(unsigned int i {0}; i < A.size(); i++)
{
if(A[i] <= 0) //If negative
{
index = (A.size() - first_pos) - abs(A[i]);
} else
{
index = (A[i] + 1) + first_pos;
}
if(A[i] == V[index])
{
V[index] = 0;
}
}
return *std::min_element(V.begin(), V.end());
}
//Output: -3
Solution Two fails to compare the values of the two vectors (A and V), as calculating the index with the above methods with a positive int doesn't work.
1) How can I get my Solution 2 to work with unordered vector's of negative int's?
2) How can I edit my Solution 2 to work with vectors of positive as well as vectors with negative int's?
Your first solution seems O(max(N,M)), where I consider N the number of elements in vector A and M the size of vector V (or max(Ai)), but you are looping through both vectors multiple times (with std::min_element, std::max_element, the for loop, the allocation of V and std::iota too).
Besides, once corrected a couple of typos (a missing ; and an into instead of int), your program returns the value found... from main(), which is a bit odd.
Your first algorithm always searches for the lowest missing value in the range [1, max value in A], but it can be generalized to find the lowest missing element in the range [min(Ai), max(Ai)], even for negative numbers.
My approach is similar to that of L.Senioins, but I've used different library functions trying to minimize the number of loops.
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
template <class ForwardIt>
typename std::iterator_traits<ForwardIt>::value_type
lowest_missing(ForwardIt first, ForwardIt last)
{
if ( first == last )
throw std::string {"The range is empty"};
// find both min and max element with one function
auto result = std::minmax_element(first, last);
// range is always > 0
auto range = *result.second - *result.first + 1;
if ( range < 2 )
throw std::string {"Min equals max, so there are no missing elements"};
std::vector<bool> vb(range); // the initial value of all elements is false
for (auto i = first; i != last; ++i)
vb[*i - *result.first] = true;
// search the first false
auto pos = std::find(vb.cbegin(), vb.cend(), false);
if ( pos == vb.cend() ) // all the elements are true
throw std::string {"There are no missing elements"};
return std::distance(vb.cbegin(), pos) + *result.first;
}
template <class ForwardIt>
void show_the_first_missing_element(ForwardIt first, ForwardIt last)
{
try
{
std::cout << lowest_missing(first, last) << '\n';
}
catch(const std::string &msg)
{
std::cout << msg << '\n';
}
}
int main() {
std::vector<int> a { 1, 8, 9, 6, 2, 5, 3, 0 };
show_the_first_missing_element(a.cbegin(), a.cend());
std::vector<int> b { -1, -4, 8, 1, -3, -2, 10, 0 };
show_the_first_missing_element(b.cbegin(), b.cend());
show_the_first_missing_element(b.cbegin() + b.size() / 2, b.cend());
std::vector<int> c { -2, -1, 0, 1, 2, 3 };
show_the_first_missing_element(c.cbegin(), c.cend());
std::vector<int> d { 3, 3, 3 };
show_the_first_missing_element(d.cbegin(), d.cend());
std::vector<int> e;
show_the_first_missing_element(e.cbegin(), e.cend());
return 0;
}
The results outputted for my test cases are:
4
2
-1
There are no missing elements
Min equals max, so there are no missing elements
The range is empty
My solution is to make a bool vector (or char vector just to avoid compilation warnings about casting to bool) which has the size of all possible elements. All elements are initialized to 0 and later are assigned to 1 which indicates that the element is not missing. All you need to do then is to find an index of the first 0 element which is the lowest missing element.
#include <vector>
#include <algorithm>
#include <iostream>
std::vector<int> A{ -1, 0, 11, 1, 10, -5 };
int main() {
if (A.size() > 1) {
int max_el = *std::max_element(A.begin(), A.end());
int min_el = *std::min_element(A.begin(), A.end());
int range = abs(max_el - min_el) + 1;
std::vector<int> V(range, 0);
for (size_t i = 0; i < A.size(); i++)
V[A[i] - min_el] = 1;
if (*std::min_element(V.begin(), V.end()) == 0)
std::cout << std::distance(V.begin(), std::find(V.begin(), V.end(), 0)) + min_el;
else
std::cout << "There are no missing elements" << std::endl;
}
else
std::cout << "There are no missing elements" << std::endl;
std::cin.get();
}
I'm going to try give my own question an answer, after spending sometime thinking about this:
int main()
{
std::vector<int> A {-3, -1, 0, 1, 3, 4};
auto relative_pos = std::minmax_elment(A.begin(), A.end());
std::vector<bool> Litmus( *(relative_pos.second) - *(relative_pos.first), false); //Create vector of size max val - min val)
auto lowest_val = *(relative_pos.first);
for(auto x : A)
{
Litmus[i - lowest_val] = true;
}
auto pos = std::find(Litmus.begin(), Litmus.end(), false); //Find the first occurring false value
std::cout<< (pos - Litmus.begin()) + lower<<std::endl; //Print the val in A relative to false value in Litmus
}
This solution works with negative numbers and is linear.
#include <vector>
#include <iostream>
#include <string>
#include <algorithm>
#include <numeric>
int solution(vector<int> &A) {
std::vector<int>::iterator it = std::max_element(A.begin(),A.end());
try
{
sort(A.begin(),A.end());
std::vector<int>::iterator it = std::unique(A.begin(),A.end());
A.resize(std::distance(A.begin(),it));
for(int i = 0, j = 1; i < A.size(); i++)
{
if( A[i] != j)
{
return j;
}
j++;
}
}
catch(exception &e)
{
std::cout<<e.what()<<std::endl;
}
return ++(*it);
}
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