I am trying to solve the following problem using C++ - c++

The objective is to return all pairs of integers from a given array of integers that have a difference of 2. The result array should be sorted in ascending order of values. Assume there are no duplicate integers in the array. The order of the integers in the input array should not matter.
My code here:
#include <utility>
#include <bits/stdc++.h>
#include <vector>
using namespace std;
std::vector<std::pair<int, int>> twos_difference(const std::vector<int> &vec) {
vector <int> v1 = vec;
vector <pair<int,int>> pairs;
sort(v1.begin(),v1.end(), greater<int>());
for (size_t i=0; i<vec.size()-1; i++){
pair <int,int> due;
for (size_t j=1; j<vec.size(); j++){
if (v1[i] - v1[j] == 2){
due.first = v1[j];
due.second = v1[i];
pairs.push_back(due);
break;
}
}
}
sort(pairs.begin(),pairs.end());
return pairs;""
}
Execution Timed Out (12000 ms) WHY??????

We are here to help.
I analysed the code and checked, what could be the issue here.
From this, you can derive measures for improvements.
Please check the below list, maybe this gives you and idea for further development.
You pass the input vector by reference, but then copy all the data. No need to do. Use the given input vector as is. Except, of course, if the source data is still neded
You define your resulting std::vector "pairs" but do not reserve memory for this. Using push_back on this std::vector will do a lot of memory reallocation and copying. Please use std::pairs.reserve(vec.size()/2);after the definition of "pairs".
No need to handover "greater" to the sort function. The sort function will do that by default
Double nested loops are not needed. Your values are already sorted. You can use a single loop and then compare vec[i] with [vec[i+1]. This will reduce the complexity from quadratic to linear.
At the end, you sort again the pairs. This is not necessary, as the values were already sorted before
Please compile with all optimizations on, like "Release Mode" or "-O3"
See the below example which creates fist 10.000.000 random and unique test values and then measures the execution of the operation for finding the required pairs.
Execution time is below 1 second on my machine.
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <random>
#include <unordered_set>
#include <limits>
#include <chrono>
#include <fstream>
constexpr size_t MaxValues = 10'000'000;
std::vector<int> createTestValues() {
std::random_device rd; // Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> distrib(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
std::unordered_set<int> values{};
while (values.size() < MaxValues)
values.insert(distrib(gen));
return { values.begin(), values.end() };
}
int main() {
std::vector values = createTestValues();
auto start = std::chrono::system_clock::now();
// Main algorithm ------------------------------------------
std::vector<std::pair<int, int>> result;
result.reserve(values.size() / 2);
std::sort(values.begin(), values.end());
for (size_t k{}; k < values.size() - 1; ++k)
if (values[k + 1] - values[k] == 2)
result.push_back({ values[k] , values[k + 1] });
// ------------------------------------------------------
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start);
std::cout << "Elapsed time: " << elapsed.count() << " ms\n\n";
std::ofstream ofs{ "test.txt" };
for (const auto& [v1, v2] : result) ofs << v1 << '\t' << v2 << '\n';
}

Related

Iterator printing from vector unneeded values

The intended nature of the program is to randomly generate numbers into a vector container, then sort them in ascending order and print the numbers out. The program compiles correctly but also sorts and prints the value 0 for each number that is generated.
#include "stdafx.h"
//contains all header files (ctime, algorithm, iostream, vector), also
defines const vector size as 250
using namespace std;
void genRndNums(vector <int> &v);
void printVec(vector <int> &v);
int main()
{
vector <int> myVector(VEC_SIZE);
genRndNums(myVector);
printVec(myVector);
return 0;
}
void genRndNums(vector <int> &v)
{
int v1;
srand(time(nullptr));
for (int i = 0; i < VEC_SIZE; i++)
{
v1 = rand() % 1000 + 1;
v.push_back(v1);
//v.push_back(rand() % 1000 + 1);
}
}
void printVec(vector <int> &v)
{
vector<int>::iterator it;
sort(v.begin(), v.end());
for (it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
}
In the case that 250 numbers were printed out, it would display the integer 0 250 times and then display the rest of the numbers in ascending sequence.
This is due to the for-loop in the print function having something misplaced, but I am not sure how to get the vector to display only the randomized integers.
Since you are using push_back to add elements to the vector, you need to start with an empty vector. I.e. you need to replace vector <int> myVector(VEC_SIZE); with vector <int> myVector;.
This is a common mistake. push_back adds to the end of the vector whose size is already VEC_SIZE. You can start with an empty vector like this:
vector <int> myVector;
or you can assign values to existing vector (whose size is VEC_SIZE) elements like this:
for (int i = 0; i < VEC_SIZE; i++)
{
v1 = rand() % 1000 + 1;
v[i] = v1;
}
Your vector constructor creates vector with 250 numbers (each with 0 value). To that numbers you appends another 250 generated numbers.
You shall not create that 250 numbers at the beginning
#include <vector>
#include <algorithm>
#include <random>
#include <iostream>
int main()
{
std::vector<int> v;
{
std::random_device r;
std::default_random_engine e(r());
std::uniform_int_distribution<int> d(1, 6);
std::generate_n(std::back_inserter(v), 250, [&](){ return d(r); });
}
std::sort(v.begin(), v.end());
for (auto x : v) {
std::cout << x << "\n";
}
return 0;
}
or override them
#include <vector>
#include <algorithm>
#include <random>
#include <iostream>
int main()
{
std::vector<int> v(250);
{
std::random_device r;
std::default_random_engine e(r());
std::uniform_int_distribution<int> d(1, 6);
std::generate(v.begin(), v.end(), [&](){ return d(r); });
}
std::sort(v.begin(), v.end());
for (auto x : v) {
std::cout << x << "\n";
}
return 0;
}

Is it possible to select random numbers from a defined set of numbers

Random function usually generates random numbers within a given range. But is it possible to randomly select from a pre-defined list? For example i have [1,4,5,6] and i want to randomly select from this list only. If so, how?
Thanks :)
P.s:: C++ code would help me a big deal ^^
The following code would help, instead of choose a random integer, we can choose a random index in the set;
int numbers[4] = {1,4,5,6};
srand (time(NULL));
int index = rand() % 4;
int number = numbers[index];
Here is a C++11 version utilizing <random> instead:
#include <random>
int numbers[4] = {1,4,5,6};
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(0,3);
int index = distribution(generator); // generates number in the range 0..3
int number = numbers[index];
Good way to do that might be using shuffle. Basically, you shuffle array and then start to pick numbers one by one
#include <iostream> // std::cout
#include <algorithm> // std::shuffle
#include <array> // std::array
#include <random> // std::default_random_engine
int main () {
std::array<int, 4> foo {1,4,5,6};
std::shuffle(foo.begin(), foo.end(), std::default_random_engine(12345));
std::cout << "shuffled elements:";
for (int x: foo)
std::cout << ' ' << x;
std::cout << '\n';
return 0;
}

exclude non-duplicated int in vector

I'm new to C++, I came from Swift background, and I'm thankful for your help in advance.
I have a vector that contains int values. Some of them are repeated.
My task here is to get the largest repeated value from the vector.
Example:
std::vector<int> myVector;
myVector.push_back(1);
myVector.push_back(8);
myVector.push_back(4);
myVector.push_back(4);
I need a function that returns 4 because it's the largest duplicate int in the vector.
Thanks again, and please, if you have any question, please ask it instead of downvoting.
Solution based only on std algorithms:
Sort the list using std::sort.
Iterate backwards over its elements and detect the first one that is equal to its predecessor using std::adjacent_find and reverse iterators.
I doubt it gets simpler than this. For your enjoyment:
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{1,2,3,3,4,4,4,5,6,7,7,8};
std::sort(v.begin(), v.end());
auto result = std::adjacent_find(v.rbegin(), v.rend());
if(result == v.rend())
std::cout << "No duplicate elements found.";
else
std::cout << "Largest non-unique element: " << *result;
}
Live example on Coliru.
Properties:
Zero space overhead if the list can be sorted in place.
Complexity: O(N log(N)) less than comparisons and K equality comparisons where K is equal to the number of unique elements larger than the one you're after.
Lines of code making up the algorithm: 2
You could use a map, as someone who commented above, and then place the number of appearances of each element of the vector. Afterwards, you take the maximum element via a custom comparator.
Ideone
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
int largestRepeatingNumber(const std::vector<int> & vec)
{
std::map<int, int> counter;
std::for_each(std::begin(vec), std::end(vec), [&counter] (int elem) {
counter.find(elem) == counter.end() ? counter[elem] = 1 : ++counter[elem]; });
return std::max_element(std::begin(counter), std::end(counter), [] (auto lhs, auto rhs) {
if (lhs.second == rhs.second)
return lhs.first < rhs.first;
return lhs.second < rhs.second;
})->first;
}
int main()
{
std::vector<int> myVector;
myVector.push_back(1);
myVector.push_back(8);
myVector.push_back(4);
myVector.push_back(4);
myVector.push_back(3);
myVector.push_back(3);
std::cout << largestRepeatingNumber(myVector);
return 0;
}
I have used the lower bound and upper bound
so strategy is
1)Sort the original vector (so that can use unique function on it)
2)find unique (copy the unique values to a vector so that we can use it to find the values in original vector , not extra search)
3)Find the lower and upper bound value with max distance
for example 1 4 4 8
4 will have max distance
5)Store in map using the count as index (map is ordered so max duplicate value will be at the end )
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
int main()
{
std::vector<int> myVector,myvec,counter;
map<int,int> maxdupe;
myVector.push_back(1);
myVector.push_back(8);
myVector.push_back(4);
myVector.push_back(4);
sort(myVector.begin(),myVector.end());
std::unique_copy(myVector.begin(), myVector.end(), std::back_inserter(myvec));
std::copy(myvec.begin(), myvec.end(), std::ostream_iterator<int>(std::cout, " "));
cout<<endl;
for(auto i = myvec.begin(); i!=myvec.end();i++)
{
auto lower = std::lower_bound(myVector.begin(), myVector.end(), *i);
auto upper = std::upper_bound(myVector.begin(), myVector.end(), *i);
maxdupe[upper - lower] = *i;
}
for(auto i= maxdupe.begin();i!= maxdupe.end();i++)
{
cout<<i->first<<i->second<<endl;
}
return 0;
}
Output
1 4 8
18
24
Program ended with exit code: 0

Extract values from a set according to a given probability distribution

I have to tackle this problem:
vector<int> myset={1,2,3,4};
vector<double> distribution ={0.01,0.1,0.3,0.59};
I have to pick a number of values from myset according to given distribution. Actually distribution and myset aren't fixed. They are of the same dimension, but this dimension can change and be pretty large too. I could uniformly extract a number in the range [0 100] and do like this:
int extracted_numb;
int numb = rand(0,100);
if(numb<1)
extracted_numb=myset[0];
else if(numb<11)
extracted_numb=myset[1];
else if(numb<41)
extracted_numb=myset[2];
else
extracted_numb=myset[3];
But I repeat, I don't know in the real case the dimension of distribution and myset (because is a user parameter) and thus I don't know how many if to do.
I ask if there is a good algorithm for this problem, and maybe some native library of C++ or in Boost that already accomplish it
(I'm using Boost 1.63 and C++11)
With C++11, use random::discrete_distribution to select an index into myset. (Boost has a similar function.)
Example (adapted from the cppreference link):
#include <iostream>
#include <map>
#include <random>
#include <vector>
int main()
{
std::vector<int> myset = {10,22,35,47};
std::vector<double> distribution = {0.01,0.1,0.3,0.59};
std::random_device rd;
std::mt19937 gen(rd());
std::discrete_distribution<> d(distribution.begin(), distribution.end());
std::map<int, int> m;
for(int n=0; n<10000; ++n) {
++m[myset[d(gen)]];
}
for(auto p : m) {
std::cout << p.first << " generated " << p.second << " times\n";
}
}
(Live on coliru)

boost zip_iterator and std::sort

I have two arrays values and keys both of the same length.
I want to sort-by-key the values array using the keys array as keys.
I have been told the boost's zip iterator is just the right tool for locking two arrays together and doing stuff to them at the same time.
Here is my attempt at using the boost::zip_iterator to solve sorting problem which fails to compile with gcc. Can someone help me fix this code?
The problem lies in the line
std::sort ( boost::make_zip_iterator( keys, values ), boost::make_zip_iterator( keys+N , values+N ));
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
int main(int argc, char *argv[])
{
int N=10;
int keys[N];
double values[N];
int M=100;
//Create the vectors.
for (int i = 0; i < N; ++i)
{
keys[i] = rand()%M;
values[i] = 1.0*rand()/RAND_MAX;
}
//Now we use the boost zip iterator to zip the two vectors and sort them "simulatneously"
//I want to sort-by-key the keys and values arrays
std::sort ( boost::make_zip_iterator( keys, values ),
boost::make_zip_iterator( keys+N , values+N )
);
//The values array and the corresponding keys in ascending order.
for (int i = 0; i < N; ++i)
{
std::cout << keys[i] << "\t" << values[i] << std::endl;
}
return 0;
}
NOTE:Error message on compilation
g++ -g -Wall boost_test.cpp
boost_test.cpp: In function ‘int main(int, char**)’:
boost_test.cpp:37:56: error: no matching function for call to ‘make_zip_iterator(int [(((unsigned int)(((int)N) + -0x00000000000000001)) + 1)], double [(((unsigned int)(((int)N) + -0x00000000000000001)) + 1)])’
boost_test.cpp:38:64: error: no matching function for call to ‘make_zip_iterator(int*, double*)’
You can't sort a pair of zip_iterators.
Firstly, make_zip_iterator takes a tuple of iterators as input, so you could call:
boost::make_zip_iterator(boost::make_tuple( ... ))
but that won't compile either, because keys and keys+N doesn't have the same type. We need to force keys to become a pointer:
std::sort(boost::make_zip_iterator(boost::make_tuple(+keys, +values)),
boost::make_zip_iterator(boost::make_tuple(keys+N, values+N)));
this will compile, but the sorted result is still wrong, because a zip_iterator only models a Readable iterator, but std::sort also needs the input to be Writable as described here, so you can't sort using zip_iterator.
A very good discussion of this problem can be found here: https://web.archive.org/web/20120422174751/http://www.stanford.edu/~dgleich/notebook/2006/03/sorting_two_arrays_simultaneou.html
Here's a possible duplicate of this question: Sorting zipped (locked) containers in C++ using boost or the STL
The approach in the link above uses std::sort, and no extra space. It doesn't employ boost::zip_iterator, just boost tuples and the boost iterator facade. Std::tuples should also work if you have an up to date compiler.
If you are happy to have one extra vector (of size_t elements), then the following approach will work in ~ o(n log n) time average case. It's fairly simple, but there will be better approaches out there if you search for them.
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
template <typename T1, typename T2>
void sortByPerm(vector<T1>& list1, vector<T2>& list2) {
const auto len = list1.size();
if (!len || len != list2.size()) throw;
// create permutation vector
vector<size_t> perms;
for (size_t i = 0; i < len; i++) perms.push_back(i);
sort(perms.begin(), perms.end(), [&](T1 a, T1 b){ return list1[a] < list1[b]; });
// order input vectors by permutation
for (size_t i = 0; i < len - 1; i++) {
swap(list1[i], list1[perms[i]]);
swap(list2[i], list2[perms[i]]);
// adjust permutation vector if required
if (i < perms[i]) {
auto d = distance(perms.begin(), find(perms.begin() + i, perms.end(), i));
swap(perms[i], perms[d]);
}
}
}
int main() {
vector<int> ints = {32, 12, 40, 8, 9, 15};
vector<double> doubles = {55.1, 33.3, 66.1, 11.1, 22.1, 44.1};
sortByPerm(ints, doubles);
copy(ints.begin(), ints.end(), ostream_iterator<int>(cout, " ")); cout << endl;
copy(doubles.begin(), doubles.end(), ostream_iterator<double>(cout, " ")); cout << endl;
}
After seeing another of your comments in another answer.
I though I would enlighten you to the std::map. This is a key value container, that preserves key order. (it is basically a binary tree, usually red black tree, but that isn't important).
size_t elements=10;
std::map<int, double> map_;
for (size_t i = 0; i < 10; ++i)
{
map_[rand()%M]=1.0*rand()/RAND_MAX;
}
//for every element in map, if you have C++11 this can be much cleaner
for (std::map<int,double>::const_iterator it=map_.begin();
it!=map_.end(); ++it)
{
std::cout << it->first << "\t" << it->second << std::endl;
}
untested, but any error should be simple syntax errors
boost::make_zip_iterator take a boost::tuple.
#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
int main(int argc, char *argv[])
{
std::vector<int> keys(10); //lets not waste time with arrays
std::vector<double> values(10);
const int M=100;
//Create the vectors.
for (size_t i = 0; i < values.size(); ++i)
{
keys[i] = rand()%M;
values[i] = 1.0*rand()/RAND_MAX;
}
//Now we use the boost zip iterator to zip the two vectors and sort them "simulatneously"
//I want to sort-by-key the keys and values arrays
std::sort ( boost::make_zip_iterator(
boost::make_tuple(keys.begin(), values.begin())),
boost::make_zip_iterator(
boost::make_tuple(keys.end(), values.end()))
);
//The values array and the corresponding keys in ascending order.
for (size_t i = 0; i < values.size(); ++i)
{
std::cout << keys[i] << "\t" << values[i] << std::endl;
}
return 0;
}