We have a set S {1,10,100,1000,10000}. Now we input an integer x (say x = 4).
Now we have to add every element of set's product with x to the set itself. So finally
S={1,10,100,1000,10000,4,40,400,4000,40000}
[S is not limited to only 5 entries initially]
We have to visit only the initial elements in the set.
I tried an approach like:
for(auto i=s.begin();i!=s.end();i++)
{
s.insert((*i)*x);
}
This doesnt give the desired result, as the size of set keeps increasing.
Another approach I tried was to store all the multiples (*i)*x in another temporary set/vector and to merge it with s later.
But since the original dataset is huge, it worsens the time complexity.
Any optimizations ?
Since the std::set is ordered, and iterators are not invalidated by insertion, you can simply insert while iterating as long as you don't insert to the range that is still left to be iterated.
If we can assume all numbers to be positive, then we can iterate in reverse direction, because the result of multiplication is always going to be greater than the inputs:
for (auto it = S.rbegin(); it != S.rend(); ++it)
S.insert(*it*x);
If x is negative and set contains only positive, then order of iteration doesn't matter. If the set may contain negative numbers, this becomes more challenging.
But since the original dataset is huge, it worsens the time complexity.
Inserting N elements into std::set is O(N log N). Merging std::sets is O(N log N). The merge approach does not worsen asymptotic time complexity.
If you were to use an std::unordered_set though, the merge approach would be O(N) in average case. It's still O(N log N) in worst case however. I recommend using the merge approach with an unordered set.
Here you are.
#include <iostream>
#include <set>
#include <iterator>
std::set<int> & update( std::set<int> &s, int value )
{
for ( auto it = rbegin( s ); it != rend( s ); ++it )
{
s.insert( *it * value );
}
return s;
}
int main()
{
std::set<int> s = { 1, 10, 100, 1000, 10000 };
for ( const auto &value : s )
{
std::cout << value << ' ';
}
std::cout << '\n';
for ( const auto &value : update( s, 4 ) )
{
std::cout << value << ' ';
}
std::cout << '\n';
return 0;
}
The program output is
1 10 100 1000 10000
1 4 10 40 100 400 1000 4000 10000 40000
According to the C++ 20 Standard (22.2.6 Associative containers)
9 The insert and emplace members shall not affect the validity of
iterators and references to the container, and the erase members shall
invalidate only iterators and references to the erased elements.
Or a more general approach
#include <iostream>
#include <set>
#include <iterator>
std::set<int> & update( std::set<int> &s, int value )
{
auto partition = s.lower_bound( 0 );
for ( auto it = rbegin( s ); it != std::set<int>::reverse_iterator( partition ); ++it )
{
s.insert( *it * value );
}
for ( auto it = begin( s ); it != partition; ++it )
{
s.insert( *it * value );
}
return s;
}
int main()
{
std::set<int> s = { -10000, -1000, -100, -10, -1, 1, 10, 100, 1000, 10000 };
for ( const auto &value : s )
{
std::cout << value << ' ';
}
std::cout << '\n';
for ( const auto &value : update( s, 4 ) )
{
std::cout << value << ' ';
}
std::cout << '\n';
return 0;
}
The program output is
-10000 -1000 -100 -10 -1 1 10 100 1000 10000
-40000 -10000 -4000 -1000 -400 -100 -40 -10 -4 -1 1 4 10 40 100 400 1000 4000 10000 40000
As mentioned in the comments, it's simplest to use a temporary set. With C++17, you can use std::set::merge with the temporary set casted to an rvalue:
#include <algorithm>
std::set<int> s2;
std::transform(s1.cbegin(), s1.cend(), std::inserter(s2, s2.end()),
[](int orig){ return 4*orig; });
s1.merge(std::move(s2));
Otherwise, note that iterators into the set aren't invalidated while inserting. Take this together with the fact that the set is ordered and in case of the scenario you described (scaling an existing value is larger than the original value, but less or equal than the next existing one), you can do it in a loop like this:
for (auto it = s1.begin(); it != s1.end(); ++it)
it = s.insert(*it*4).first;
For fewer restrictions, you can use this more verbose loop:
for (std::set<int>::iterator it1 = s.begin(), it2; it1 != s.end();
it1 = std::next(it1) == it2 ? std::next(it1, 2) : it2)
it2 = s.insert(*it1*4).first;
Related
I have this problem: Given a vector with n numbers, sort the numbers so that the even ones will be on odd positions and the odd numbers will be on even positions. E.g. If I have the vector 2 6 7 8 9 3 5 1, the output should be 2 7 6 9 8 3 5 1 . The count should start from 1. So on position 1 which is actually index 0 should be an even number, on position 2 which is actually index 1 should be an odd number and so on. Now this is easy if the odd and even numbers are the same, let's say 4 even number and 4 odd numbers in the vector, but what if the number of odd numbers differs from the number of even numbers like in the above example? How do I solve that. I attached the code with one of the tries I did, but it doesn't work. Can I get some help please. I ask you to keep it simple that means only with vectors and such. No weird methods or anything cause I'm a beginner and I only know the basics. Thanks in advance!
I have to mention that n initial is globally declared and is the number of vector elements and v_initial is the initial vector with the elements that need to be rearranged.
The task says to add the remaining numbers to the end of the vector. Like if there are 3 odd and 5 even numbers, The 2 extra even numbers should be thrown at the end of the vector
void vector_pozitii_pare_impare(int v_initial[])
{
int v_pozitie[50],c1=0,c2=1;
for (i = 0; i < n_initial; i++)
{
if (v_initial[i] % 2 == 0)
{
bool isTrue = 1;
for (int k = i + 1; k < n_initial; k++)
{
if (v_initial[k] % 2 != 0)
isTrue = 0;
}
if (isTrue)
{
v_pozitie[c1] = v_initial[i];
c1++;
}
else
{
v_pozitie[c1] = v_initial[i];
c1 += 2;
}
}
else
{
bool isTrue = 1;
for (int j = i + 1; j < n_initial; j++)
{
if (v_initial[j] % 2 == 0)
{
isTrue = 0;
}
if (isTrue)
{
v_pozitie[c2] = v_initial[i];
c2++;
}
else
{
v_pozitie[c2] = v_initial[i];
c2 += 2;
}
}
}
}
This may not be a perfect solution and it just popped out right off my mind without being tested or verified, but it's just to give you an idea.
(Let A,B,C,D be odd numbers and 0,1,2 even numbers correspondingly)
Given:
A 0 B C D 1 2 (random ordered list of odd/even numbers)
Wanted:
A 0 B 1 C 2 D (input sequence altered to match the wanted odd/even criteria)
Next, we invent the steps required to get from given to wanted:
// look at 'A' -> match, next
// Result: A 0 B C D 1 2
// look at '0' -> match, next
// Result: A 0 B C D 1 2
// look at 'B' -> match, next
// Result: A 0 B C D 1 2
// look at 'C' -> mismatch, remember index and find first match starting from index+1
// Result: A 0 B C D ->1<- 2
// now swap the numbers found at the remembered index and the found one.
// Result: A 0 B 1 D C 2
// continue until the whole list has been consumed.
As I said, this algorithm may not be perfect, but my intention is to give you an example on how to solve these kinds of problems. It's not good to always think in code first, especially not with a problem like this. So you should first think about where you start, what you want to achieve and then carefully think of how to get there step by step.
I feel I have to mention that I did not provide an example in real code, because once you got the idea, the execution should be pretty much straight forward.
Oh, and just a small remark: Almost nothing about your code is C++.
A simple solution, that is not very efficient would be to split the vector into 2 vectors, that contain even and uneven numbers and then always take one from the even, one from the uneven and then the remainder, from the one that is not completely entered.
some c++ (that actually uses vectors, but you can use an array the same way, but need to change the pointer arithmetic)
I did not test it, but the principle should be clear; it is not very efficient though
EDIT: The answer below by #AAAAAAAAARGH outlines a better algorithmic idea, that is inplace and more efficient.
void change_vector_even_uneven(std::vector<unsigned>& in_vec){
std::vector<unsigned> even;
std::vector<unsigned> uneven;
for (auto it = in_vec.begin(); it != in_vec.end(); it++){
if ((*it) % 2 == 0)) even.push_back(*it);
else uneven.push_back(*it);
}
auto even_it = even.begin();
auto uneven_it = uneven.begin();
for (auto it = in_vec.begin(); it != in_vec.end(); it++){
if (even_it == even.end()){
(*it) = (*uneven_it);
uneven_it++;
continue;
}
if (uneven_it == uneven.end()){
(*it) = (*even_it);
even_it++;
continue;
}
if ((it - in_vec.begin()) % 2 == 0){
(*it) = (*even_it);
even_it++;
}
else{
(*it) = (*uneven_it);
uneven_it++;
}
}
}
The solutions is simple. We sort the even and odd values into a data structure. In a loop, we iterate over all source values. If they are even (val & 2 == 0) we add them at the end of a std::deque for evens and if odd, we add them to a std::deque for odds.
Later, we we will extract the the values from the front of the std::deque.
So, we have a first in first out principle.
The std::deque is optimized for such purposes.
Later, we make a loop with an alternating branch in it. We, alternatively extract data from the even queue and then from the odd queue. If a queue is empty, we do not extract data.
We do not need an additional std::vector and can reuse the old one.
With that, we do not need to take care for the same number of evens and odds. It will of course always work.
Please see below one of millions of possible solutions:
#include <iostream>
#include <vector>
#include <deque>
int main() {
std::vector testData{ 2, 6, 7, 8, 9, 3, 5, 1 };
// Show initial data
std::cout << "\nInitial data: ";
for (const int i : testData) std::cout << i << ' ';
std::cout << '\n';
// We will use a deques to store odd and even numbers
// With that we can efficiently push back and pop front
std::deque<int> evenNumbers{};
std::deque<int> oddNumbers{};
// Sort the original data into the specific container
for (const int number : testData)
if (number % 2 == 0)
evenNumbers.push_back(number);
else
oddNumbers.push_back(number);
// Take alternating the data from the even and the odd values
bool takeEven{ true };
for (size_t i{}; !evenNumbers.empty() && !oddNumbers.empty(); ) {
if (takeEven) { // Take even numbers
if (not evenNumbers.empty()) { // As long as there are even values
testData[i] = evenNumbers.front(); // Get the value from the front
evenNumbers.pop_front(); // Remove first value
++i;
}
}
else { // Now we take odd numbers
if (not oddNumbers.empty()) { // As long as there are odd values
testData[i] = oddNumbers.front(); // Get the value from the front
oddNumbers.pop_front(); // Remove first value
++i;
}
}
// Next take the other container
takeEven = not takeEven;
}
// Show result
std::cout << "\nResult: ";
for (const int i : testData) std::cout << i << ' ';
std::cout << '\n';
return 0;
}
Here is yet another solution (using STL), in case you want a stable result (that is, the order of your values is preserved).
#include <algorithm>
#include <vector>
auto ints = std::vector<int>{ 2, 6, 7, 8, 9, 3, 5, 1 };
// split list to even/odd sections -> [2, 6, 8, 7, 9, 3, 5, 1]
const auto it = std::stable_partition(
ints.begin(), ints.end(), [](auto value) { return value % 2 == 0; });
auto results = std::vector<int>{};
results.reserve(ints.size());
// merge both parts with equal size
auto a = ints.begin(), b = it;
while (a != it && b != ints.end()) {
results.push_back(*a++);
results.push_back(*b++);
}
// copy remaining values to end of list
std::copy(a, it, std::back_inserter(results));
std::copy(b, ints.end(), std::back_inserter(results));
The result ist [2, 7, 6, 9, 8, 3, 5, 1]. The complexity is O(n).
This answer, like some of the others, divides the data and then reassembles the result. The standard library std::partition_copy is used to separate the even and odd numbers into two containers. Then the interleave function assembles the result by alternately copying from two input ranges.
#include <algorithm>
#include <iostream>
#include <vector>
template <typename InIt1, typename InIt2, typename OutIt>
OutIt interleave(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt dest)
{
for (;;) {
if (first1 == last1) {
return std::copy(first2, last2, dest);
}
*dest++ = *first1++;
if (first2 == last2) {
return std::copy(first1, last1, dest);
}
*dest++ = *first2++;
}
}
void reorder_even_odd(std::vector<int> &data)
{
auto is_even = [](int value) { return (value & 1) == 0; };
// split
std::vector<int> even, odd;
std::partition_copy(begin(data), end(data), back_inserter(even), back_inserter(odd), is_even);
// merge
interleave(begin(even), end(even), begin(odd), end(odd), begin(data));
}
int main()
{
std::vector<int> data{ 2, 6, 7, 8, 9, 3, 5, 1 };
reorder_even_odd(data);
for (int value : data) {
std::cout << value << ' ';
}
std::cout << '\n';
}
Demo on Compiler Explorer
As suggested, I am using vectors and STL.
No need to be a great mathematician to understand v_pozitie will start with pairs of odd and even and terminate with the integers not in the initial pairs.
I am then updating three iterators in v_positie (no need of temporary containers to calculate the result) : even, odd and end,(avoiding push_back) and would code this way :
#include <vector>
#include <algorithm>
void vector_pozitii_pare_impare(std::vector<int>& v_initial, std::vector<int>& v_pozitie) {
int nodd (0), neven (0);
std::for_each (v_initial.begin (), v_initial.end (), [&nodd] (const int& n) {
nodd += n%2;
});
neven = v_initial.size () - nodd;
int npair (neven < nodd ?neven:nodd);
npair *=2;
std::vector<int>::iterator iend (&v_pozitie [npair]), ieven (v_pozitie.begin ()), iodd (&v_pozitie [1]);
std::for_each (v_initial.begin (), v_initial.end (), [&iend, &ieven, &iodd, &npair] (const int& s) {
if (npair) {
switch (s%2) {
case 0 :
*ieven++ = s;
++ieven;
break;
case 1 :
*iodd++ = s;
++iodd;
break;
}
--npair;
}
else *iend++ = s;
});
}
int main (int argc, char* argv []) {
const int N = 8;
int tab [N] = {2, 6, 7, 8, 9, 3, 5, 1};
std::vector<int> v_initial (tab, (int*)&tab [N]);
std::cout << "\tv_initial == ";
std::for_each (v_initial.begin (), v_initial.end (), [] (const int& s) {std::cout << s << " ";});
std::cout << std::endl;
std::vector<int> v_pozitie (v_initial.size (), -1);
vector_pozitii_pare_impare (v_initial, v_pozitie);
std::cout << "\tv_pozitie == ";
std::for_each (v_pozitie.begin (), v_pozitie.end (), [] (const int& s) {std::cout << s << " ";});
std::cout << std::endl;
}
the code below is used to implement bubble sort. why is template used in this case? and what is the purpose of swapped variabe. even if i remove swapped variable and swapped condition from loop code still works fine
#include <algorithm>
#include <iostream>
#include <iterator>
template <typename RandomAccessIterator>
void bubble_sort(RandomAccessIterator begin, RandomAccessIterator end) {
bool swapped = true;
while (begin != end-- && swapped) {
swapped = false;
for (auto i = begin; i != end; ++i) {
if (*(i + 1) < *i) {
std::iter_swap(i, i + 1);
swapped = true;
}
}
}
}
int main() {
int a[] = {100, 2, 56, 200, -52, 3, 99, 33, 177, -199};
bubble_sort(std::begin(a), std::end(a));
copy(std::begin(a), std::end(a), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
}
ANOTHER IMPLEMENTATION:
template<typename Iterator>
void bubbleSort(Iterator first, Iterator last)
{
Iterator i, j;
for (i = first; i != last; i++)
for (j = first; j < i; j++)
if (*i < *j)
std::iter_swap(i, j); // or std::swap(*i, *j);
}
The template is there simply for convenience of using the function with different types. Implementing the function to use iterators and not a simple array saves you a lot of trouble with pointers and sizes.
The swapped variable indicates to the algorithm that the last run from begin to the end did not result in any swaps. This means that the array is sorted already in this range (and past the end it's sorted as well because that's what was handled in the previous passes) and there is no need to loop until the begin and end iterator are the same. The algorithm will work if you remove this check but could result in a time waste in case of partially sorted arrays.
Let's look at this example:
0: {1 2 5 3 4} (begin = 0, end = 4)
1: {1 2 3 4 5} (begin = 0, end = 3)
2: {1 2 3 4 5} (begin = 0, end = 2)
3: {1 2 3 4 5} (begin = 0, end = 1)
4: {1 2 3 4 5} (begin = 0, end = 0)
You can see that after 0: the array is already sorted, but without the swapped flag the algorithm would not break and continue checking. If the flag is there after 1: the swapped flag is false and the algorithm quits.
Different containers have their own iterator types. For example for one-dimensional arrays there are used pointers as iterators while for objects of the type std::vector there are used iterators defined in this template class.
The variable swapped is used as a criteria whether the elements are already sorted. If there was not swapping of elements of the sequence when it was traversed then it means that the sequence is already sorted.
Take into account that the implementation you showed has undefined behavior due to this statement
while (begin != end-- && swapped) {
^^^^
because there is an attempt to decrement the last iterator when the range can be empty. So the implementation is incorrect.
Moreover the algorithm is not efficient. For example a tail of the array can be already sorted after some iteration of the internal loop. However in the external loop the last iterator is moved left only one position.
It is enough to use forward iterators for the bubble sort. In this case you can use the algorithm even with std::forward_list and others containers that do not have random access iterators.
Here is a demonstrative program that shows how the algorithm can be implemented using forward iterators.
#include <iostream>
#include <algorithm>
#include <iterator>
#include <forward_list>
template <typename ForwardIterator>
void bubble_sort( ForwardIterator first, ForwardIterator last )
{
for ( ForwardIterator sorted = first; first != last; last = sorted )
{
sorted = first;
for ( ForwardIterator current = first, prev = first; ++current != last; ++prev )
{
if ( *current < *prev )
{
std::iter_swap( current, prev );
sorted = current;
}
}
}
}
int main()
{
int a[] = { 100, 2, 56, 200, -52, 3, 99, 33, 177, -199 };
bubble_sort( std::begin( a ), std::end( a ) );
std::copy( std::begin( a ), std::end( a ),
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << "\n";
std::forward_list<int> lst = { 100, 2, 56, 200, -52, 3, 99, 33, 177, -199 };
bubble_sort( std::begin( lst ), std::end( lst ) );
std::copy( std::begin(lst ), std::end( lst ),
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << "\n";
}
The program output is
-199 -52 2 3 33 56 99 100 177 200
-199 -52 2 3 33 56 99 100 177 200
Here in the program there are used an array and an object of the type std::forward_list and the algorithm can be applied to the both containers.
I have an array of n integers (not necessarily distinct!) and I would like to iterate over all subsets of size k. However I'd like to exclude all duplicate subsets.
e.g.
array = {1,2,2,3,3,3,3}, n = 7, k = 2
then the subsets I want to iterate over (each once) are:
{1,2},{1,3},{2,2},{2,3},{3,3}
What is an efficient algorithm for doing this?
Is a recursive approach the most efficient/elegant?
In case you have a language-specific answer, I'm using C++.
The same (or almost the same) algorithm which is used to generated combinations of a set of unique values in lexicographical order can be used to generate combinations of a multiset in lexicographical order. Doing it this way avoids the necessity to deduplicate, which is horribly expensive, and also avoids the necessity of maintaining all the generated combinations. It does require that the original list of values be sorted.
The following simple implementation finds the next k-combination of a multiset of n values in average (and worst-case) time O(n). It expects two ranges: the first range is a sorted k-combination, and the second range is the sorted multiset. (If either range is unsorted or the values in first range do not constitute a sub(multi)set of the second range, then the behaviour is undefined; no sanity checks are made.)
Only the end iterator from the second range is actually used, but I thought that made the calling convention a bit odd.
template<typename BidiIter, typename CBidiIter,
typename Compare = std::less<typename BidiIter::value_type>>
int next_comb(BidiIter first, BidiIter last,
CBidiIter /* first_value */, CBidiIter last_value,
Compare comp=Compare()) {
/* 1. Find the rightmost value which could be advanced, if any */
auto p = last;
while (p != first && !comp(*(p - 1), *--last_value)) --p;
if (p == first) return false;
/* 2. Find the smallest value which is greater than the selected value */
for (--p; comp(*p, *(last_value - 1)); --last_value) { }
/* 3. Overwrite the suffix of the subset with the lexicographically smallest
* sequence starting with the new value */
while (p != last) *p++ = *last_value++;
return true;
}
It should be clear that steps 1 and 2 combined make at most O(n) comparisons, because each of the n values is used in at most one comparison. Step 3 copies at most O(k) values, and we know that k≤n.
This could be improved to O(k) in the case where no values are repeated, by maintaining the current combination as a container of iterators into the value list rather than actual values. This would also avoid copying values, at the cost of extra dereferences. If in addition we cache the function which associates each value iterator with an iterator to the first instance of next largest value, we could eliminate Step 2 and reduce the algorithm to O(k) even for repeated values. That might be worthwhile if there are a large number of repeats and comparisons are expensive.
Here's a simple use example:
std::vector<int> values = {1,2,2,3,3,3,3};
/* Since that's sorted, the first subset is just the first k values */
const int k = 2;
std::vector<int> subset{values.cbegin(), values.cbegin() + k};
/* Print each combination */
do {
for (auto const& v : subset) std::cout << v << ' ';
std::cout << '\n';
} while (next_comb(subset.begin(), subset.end(),
values.cbegin(), values.cend()));
Live on coliru
I like bit-twiddling for this problem. Sure, it limits you to only 32 elements in your vector, but it's still cool.
First, given a bit mask, determine the next bitmask permutation (source):
uint32_t next(uint32_t v) {
uint32_t t = v | (v - 1);
return (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1));
}
Next, given a vector and a bitmask, give a new vector based on that mask:
std::vector<int> filter(const std::vector<int>& v, uint32_t mask) {
std::vector<int> res;
while (mask) {
res.push_back(v[__builtin_ctz(mask)]);
mask &= mask - 1;
}
return res;
}
And with that, we just need a loop:
std::set<std::vector<int>> get_subsets(const std::vector<int>& arr, uint32_t k) {
std::set<std::vector<int>> s;
uint32_t max = (1 << arr.size());
for (uint32_t v = (1 << k) - 1; v < max; v = next(v)) {
s.insert(filter(arr, v));
}
return s;
}
int main()
{
auto s = get_subsets({1, 2, 2, 3, 3, 3, 3}, 2);
std::cout << s.size() << std::endl; // prints 5
}
The basic idea of this solution is a function like next_permutation but which generates the next ascending sequence of "digits". Here called ascend_ordered.
template< class It >
auto ascend_ordered( const int n_digits, const It begin, const It end )
-> bool
{
using R_it = reverse_iterator< It >;
const R_it r_begin = R_it( end );
const R_it r_end = R_it( begin );
int max_digit = n_digits - 1;
for( R_it it = r_begin ; it != r_end; ++it )
{
if( *it < max_digit )
{
++*it;
const int n_further_items = it - r_begin;
for( It it2 = end - n_further_items; it2 != end; ++it2 )
{
*it2 = *(it2 - 1) + 1;
}
return true;
}
--max_digit;
}
return false;
}
Main program for the case at hand:
auto main() -> int
{
vector<int> a = {1,2,2,3,3,3,3};
assert( is_sorted( begin( a ), end( a ) ) );
const int k = 2;
const int n = a.size();
vector<int> indices( k );
iota( indices.begin(), indices.end(), 0 ); // Fill with 0, 1, 2 ...
set<vector<int>> encountered;
for( ;; )
{
vector<int> current;
for( int const i : indices ) { current.push_back( a[i] ); }
if( encountered.count( current ) == 0 )
{
cout << "Indices " << indices << " -> values " << current << endl;
encountered.insert( current );
}
if( not ascend_ordered( n, begin( indices ), end( indices ) ) )
{
break;
}
}
}
Supporting includes and i/o:
#include <algorithm>
using std::is_sorted;
#include <assert.h>
#include <iterator>
using std::reverse_iterator;
#include <iostream>
using std::ostream; using std::cout; using std::endl;
#include <numeric>
using std::iota;
#include <set>
using std::set;
#include <utility>
using std::begin; using std::end;
#include <vector>
using std::vector;
template< class Container, class Enable_if = typename Container::value_type >
auto operator<<( ostream& stream, const Container& c )
-> ostream&
{
stream << "{";
int n_items_outputted = 0;
for( const int x : c )
{
if( n_items_outputted >= 1 ) { stream << ", "; }
stream << x;
++n_items_outputted;
}
stream << "}";
return stream;
}
Unlike the previous answer, this is not as efficient and doesn't do anything as fancy as a lot of the bit twiddling. However it does not limit the size of your array or the size of the subset.
This solution uses std::next_permutation to generate the combinations, and takes advantage of std::set's uniqueness property.
#include <algorithm>
#include <vector>
#include <set>
#include <iostream>
#include <iterator>
using namespace std;
std::set<std::vector<int>> getSubsets(const std::vector<int>& vect, size_t numToChoose)
{
std::set<std::vector<int>> returnVal;
// return the whole thing if we want to
// choose everything
if (numToChoose >= vect.size())
{
returnVal.insert(vect);
return returnVal;
}
// set up bool vector for combination processing
std::vector<bool> bVect(vect.size() - numToChoose, false);
// stick the true values at the end of the vector
bVect.resize(bVect.size() + numToChoose, true);
// select where the ones are set in the bool vector and populate
// the combination vector
do
{
std::vector<int> combination;
for (size_t i = 0; i < bVect.size() && combination.size() <= numToChoose; ++i)
{
if (bVect[i])
combination.push_back(vect[i]);
}
// sort the combinations
std::sort(combination.begin(), combination.end());
// insert this new combination in the set
returnVal.insert(combination);
} while (next_permutation(bVect.begin(), bVect.end()));
return returnVal;
}
int main()
{
std::vector<int> myVect = {1,2,2,3,3,3,3};
// number to select
size_t numToSelect = 3;
// get the subsets
std::set<std::vector<int>> subSets = getSubsets(myVect, numToSelect);
// output the results
for_each(subSets.begin(), subSets.end(), [] (const vector<int>& v)
{ cout << "subset "; copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); cout << "\n"; });
}
Live example: http://coliru.stacked-crooked.com/a/beb800809d78db1a
Basically we set up a bool vector and populate a vector with the values that correspond with the position of the true items in the bool vector. Then we sort and insert this into a set. The std::next_permutation shuffles the true values in the bool array around and we just repeat.
Admittedly, not as sophisticated and more than likely slower than the previous answer, but it should do the job.
This question has been asked before but I cannot find it for C++.
If I have a vector and I have a starting number, does std::algorithm provide me a way to find the next highest missing number?
I can obviously write this in a nested loop, I just cant shake the feeling that I'm reinventing the wheel.
For example, given: vector foo{13,8,3,6,10,1,7,0};
The starting number 0 should find 2.
The starting number 6 should find 9.
The starting number -2 should find -1.
EDIT:
Thus far all the solutions require sorting. This may in fact be required, but a temporary sorted vector would have to be created to accommodate this, as foo must remain unchanged.
At least as far as I know, there's no standard algorithm that directly implements exactly what you're asking for.
If you wanted to do it with something like O(N log N) complexity, you could start by sorting the input. Then use std::upper_bound to find the (last instance of) the number you've asked for (if present). From there, you'd find a number that differs from the previous by more than one. From there you'd scan for a difference greater than 1 between the consecutive numbers in the collection.
One way to do this in real code would be something like this:
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
#include <iterator>
int find_missing(std::vector<int> x, int number) {
std::sort(x.begin(), x.end());
auto pos = std::upper_bound(x.begin(), x.end(), number);
if (*pos - number > 1)
return number + 1;
else {
std::vector<int> diffs;
std::adjacent_difference(pos, x.end(), std::back_inserter(diffs));
auto pos2 = std::find_if(diffs.begin() + 1, diffs.end(), [](int x) { return x > 1; });
return *(pos + (pos2 - diffs.begin() - 1)) + 1;
}
}
int main() {
std::vector<int> x{ 13, 8, 3, 6, 10, 1,7, 0};
std::cout << find_missing(x, 0) << "\n";
std::cout << find_missing(x, 6) << "\n";
}
This is somewhat less than what you'd normally think of as optimal to provide the external appearance of a vector that can/does remain un-sorted (and unmodified in any way). I've done that by creating a copy of the vector, and sorting the copy inside the find_missing function. Thus, the original vector remains unmodified. The disadvantage is obvious: if the vector is large, copying it can/will be expensive. Furthermore, this ends up sorting the vector for every query instead of sorting once, then carrying out as many queries as desired on it.
So I thought I'd post an answer. I don't know anything in std::algorithm that accomplishes this directly, but in combination with vector<bool> you can do this in O(2N).
template <typename T>
T find_missing(const vector<T>& v, T elem){
vector<bool> range(v.size());
elem++;
for_each(v.begin(), v.end(), [&](const T& i){if((i >= elem && i - elem < range.size())range[i - elem] = true;});
auto result = distance(range.begin(), find(range.begin(), range.end(), false));
return result + elem;
}
First you need to sort the vector. Use std::sort for that.
std::lower_bound finds the first element that is greater or equal with a given element. (the elements have to be at least partially ordered)
From there you iterate while you have consecutive elements.
Dealing with duplicates: One way is the way I went: consider consecutive and equal elements when iterating. Another approach is to add a prerequisite that the vector / range contains unique elements. I chose the former because it avoids erasing elements.
Here is how you eliminate duplicates from a sorted vector:
v.erase(std::unique(v.begin(), v.end()), v.end());
My implementation:
// finds the first missing element in the vector v
// prerequisite: v must be sorted
auto firstMissing(std::vector<int> const &v, int elem) -> int {
auto low = std::lower_bound(std::begin(v), std::end(v), elem);
if (low == std::end(v) || *low != elem) {
return elem;
}
while (low + 1 != std::end(v) &&
(*low == *(low + 1) || *low + 1 == *(low + 1))) {
++low;
}
return *low + 1;
}
And a generalized version:
// finds the first missing element in the range [first, last)
// prerequisite: the range must be sorted
template <class It, class T = decltype(*std::declval<It>())>
auto firstMissing(It first, It last, T elem) -> T {
auto low = std::lower_bound(first, last, elem);
if (low == last || *low != elem) {
return elem;
}
while (std::next(low) != last &&
(*low == *std::next(low) || *low + 1 == *std::next(low))) {
std::advance(low, 1);
}
return *low + 1;
}
Test case:
int main() {
auto v = std::vector<int>{13, 8, 3, 6, 10, 1, 7, 7, 7, 0};
std::sort(v.begin(), v.end());
for (auto n : {-2, 0, 5, 6, 20}) {
cout << n << ": " << firstMissing(v, n) << endl;
}
return 0;
}
Result:
-2: -2
0: 2
5: 5
6: 9
20: 20
A note about sorting: From the OP's comments he was searching for a solution that wouldn't modify the vector.
You have to sort the vector for an efficient solution. If modifying the vector is not an option you could create a copy and work on it.
If you are hell-bent on not sorting, there is a brute force solution (very very inefficient - O(n^2)):
auto max = std::max_element(std::begin(v), std::end(v));
if (elem > *max) {
return elem;
}
auto i = elem;
while (std::find(std::begin(v), std::end(v), i) != std::end(v)) {
++i;
}
return i;
First solution:
Sort the vector. Find the starting number and see what number is next.
This will take O(NlogN) where N is the size of vector.
Second solution:
If the range of numbers is small e.g. (0,M) you can create boolean vector of size M. For each number of initial vector make the boolean of that index true. Later you can see next missing number by checking the boolean vector. This will take O(N) time and O(M) auxiliary memory.
map< pair<int,int> , int > m ;
Here pair.first and pair.second are positive and pair.second >= pair.first.
I would like to find all iterator/s in map m such that for a given key. Key is an integer which lies between pairs e.g. key is 2 and pair is [2,5] and [1,2] etc.
e.g. m[1,3] = 10 , m[3,5] = 6 , m[1,8] = 9 , m[7,8] = 15 then when I search for m.find(3) then it would return iterator for m[1,3] , m[1,8] , m[3,5] .If there is no key then it would return m.end().
I'm not sure why you want to do this, but these days Boost Interval Container library is pretty capable.
Assuming that you might have wanted to keep track of the total (sum) of mapped values for a specific point, you could simply apply a splitting Combining Style to your input data and profit:
Live On Coliru
#include <boost/icl/split_interval_map.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
namespace icl = boost::icl;
int main() {
using Map = icl::split_interval_map<int, int>;
using Ival = Map::interval_type;
Map m;
m.add({Ival::closed(1,3), 10});
m.add({Ival::closed(3,5), 6});
m.add({Ival::closed(1,8), 9});
m.add({Ival::closed(7,8), 15});
for (auto e : m) std::cout << e.first << " -> " << e.second << "\n";
std::cout << "------------------------------\n";
for (auto e : boost::make_iterator_range(m.equal_range(Ival::closed(3,3))))
std::cout << e.first << " -> " << e.second << "\n";
}
This will tell us:
[1,3) -> 19
[3,3] -> 25
(3,5] -> 15
(5,7) -> 9
[7,8] -> 24
------------------------------
[3,3] -> 25
Notice how
the consolidation very accurately reflects that the point [3,3] is the only only point that coincided with both [1,3] and [3,5] from the input data simultaneously, and as a result, we get halfopen intervals in the combined set ([1,3), [3,3] and (3,5]).
Note also how the query for this one point correctly returns the sum of 10+6+9 for all the three intervals you were interested in.
What Use Is This?
So, you see I shifted the focus of the question from the "How?" to the "What?". It usually helps to state the goal of code instead of the particular mechanics.
Of course, if instead of the sum you'd have been interested in the average, the minimum or the maximum, you'd likely find yourself writing some custom combining strategy.
Bonus In case you wanted, here's how you can at least write the solution to the problem posed in the OP using Boost Icl: Live On Coliru. Though it's not particularly efficient, it's straight forward and robust.
I think that instead of iterators you could store (and use) corresponding keys of the map. If so then the code could look like
#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
#include <utility>
int main()
{
std::map<std::pair<int, int>, int> m;
m[{ 1, 3}] = 10;
m[{ 3, 5}] = 6;
m[{ 7, 8}] = 15;
typedef std::map<std::pair<int, int>, int>::value_type value_type;
typedef std::map<std::pair<int, int>, int>::key_type key_type;
int search;
auto in_range = [&search]( const value_type &value )
{
return value.first.first <= search && search <= value.first.second;
};
search = 3;
std::vector<key_type> v;
v.reserve( std::count_if( m.begin(), m.end(), in_range ) );
for ( const auto &p : m )
{
if ( in_range( p ) ) v.push_back( p.first );
}
for ( const auto &p : v )
{
std::cout << "[ " << p.first << ", " << p.second << " ]" << std::endl;
}
return 0;
}
The output is
[ 1, 3 ]
[ 3, 5 ]
Take into account that it is supposed that key.first is less than or equal to key.second where key is the key of the map.
There's no way to avoid a linear search from the start of the map, because if the first element is {0,INT_MAX} then it matches and the elements you want are not necessarily in a contiguous range, e.g. if you have {1,3},{2,2}{3,5} you only want the first and last elements when the key is 3.
You can stop searching when you reach an element with first greater than the key.
Something like this (untested):
typedef map< pair<int,int> , int > Map;
std::vector<Map::iterator>
find(int key, const Map& m)
{
std::vector<Map::iterator> matches;
for (Map::iterator it = m.begin(), end = m.end(); it != end && key <= it->first; ++it)
{
if (it.first >= key && key <= it.second)
matches.push_back(it);
}
return matches;
}
You could turn it into a functor and use find_if but I'm not sure it's worth it.
If you just want one iterator returned per call:
typedef map< pair<int,int> , int > Map;
Map::iterator
find(int key, const Map& m, Map::iterator it)
{
for (Map::iterator end = m.end(); it != end && key <= it->first; ++it)
{
if (it.first >= key && key <= it.second)
return it;
}
return m.end();
}
Map::iterator
find(int key, const Map& m)
{ return find(key, m, m.begin()); }
if you only need an iterator to the next value found in the map, you can use the std::find_if algorithm like this:
int key=2;
map<pair<int,int>, int>::iterator it =std::find_if(m.begin(),m.end(),
[key](pair<pair<int,int>,int> entry)
{
return (entry.first.first <= key)
&& (entry.first.second >= key);
}
);
cout << "the next value is: [" << it->first.first << "/";
cout << it->first.second << "] " << it->second << endl;