Solved
Thank you. This is solved. Here is the solution I used.
std::vector<int> v = {1,2,3,4,8,8,8,8,9,10}
auto p = std::lower_bound(v.begin(),b.end(),8);
int position = p - v.begin();
I want to find the first seen position of an element in a sorted vector and I want to use stl to do it.
Example: v = {1,1,2,6,7,8,8,8,8,9}
int position = my_fun(v.begin(),v.end(),8); // find the position of the first 8
Then position is 5.
Seen this is a sorted vector, I don't want to use find(), cause it will search from the starting point every time. I want to use binary_search() --- http://www.cplusplus.com/reference/algorithm/binary_search/, but binary_search will return bool only.
Any suggestions?
You could use lower_bound().
vector<int>::const_iterator pos = std::lower_bound(v.begin(), v.end(), 8);
if (pos != v.end() && *pos == 8)
return std::distance(v.begin(), pos);
return -1; // not found
You should use the lower_bound function.
int item = 8;
const auto posItr = std::lower_bound(std::begin(v), std::end(v), item);
return (posItr != std::end(stuff) && *posItr == item) ? std::distance(std::begin(stuff), posItr) : -1;
Why I used std::begin and std::end instead of the container one:
http://www.codeproject.com/Articles/570638/Ten-Cplusplus11-Features-Every-Cplusplus-Developer#beginend
You can should method std::equal_range
For example
auto p = std::equal_range( v.begin(), v.end(), 8 );
if ( p.first != p.second )
{
std::cout << "Position of the first element with value 8 is "
<< std::distance( v.begin(), p.first )
<< std::endl;
}
Or you can use std::lower_bound:
auto it = std::lower_bound( v.begin(), v.end(), 8 );
if ( it != v.end() && *it == 8 )
{
std::cout << "Position of the first element with value 8 is "
<< std::distance( v.begin(), it )
<< std::endl;
}
Related
Here is my possible implementation of the algorithm std::partition_point is :
template <typename In_It, typename FUNC>
In_It partitionPoint(In_It b, In_It e, FUNC pred){
int len = e - b;
while (len > 0){
int half = len >> 1;
In_It middle = b + half;
if( pred(*middle) ){
b = middle;
++b;
len = len - half - 1;
}
else
len = half;
}
return b;
}
My code looks like the STL one apart from using std::distance, traits... So it examines the input sequence and returns an iterator to the past-last element in the sequence for which the predicate succeeds. In other words the returned iterator denotes an element that doesn't satisfy the predicate.
int main(){
std::vector<int> v{1, 3, 5, 7, 9, 1, 3, 6, 8, 10, 12};
auto it = partitionPoint(v.begin(), v.end(), [](int x){return x % 2; });
if( it != v.cend() )
std::cout << *it << " " << it - v.cbegin() << '\n';
}
The output:
6 at index: 7
It is OK. however why I don't use directly std::find_if_not which returns an iterator to the first element for which the predicate is false?
auto it2 = findIfNot(v.cbegin(), v.cend(), [](int x){return x % 2; });
if(it2 != v.cend())
std::cout << *it2 << " at index: " << it2 - v.cbegin() << '\n';
The output:
6 at index: 7
std::find_if_not has O(N) complexity as it does a linear traversal. std::partition_point on the other hand has O(logN) complexity as it takes advantage the fact that the set is partitioned and does a binary search to find the element. Depending on the situation, this could be a big performance win.
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;
I am trying to return index in a subarray before which all elements in the subarray are divisible by some large number K (type long long). I have managed to write the correct code but the complexity is not great. Can anyone suggest a better way to do this to optimize the runtime?
long long solve (vector<long long> A, long long K, int R, int L) {
int index=L-1;
int count=0;
while(A[index]%K==0 && index<=R-1){
if(A[index]%K==0){
count++;
}
index++;
}
if(count!=0){
return (L+count-1);
}
else{
return -1;
}
}
Here, the parameters are:
L is leftmost bound of the subarray
R is rightmost bound of the subarray
A is a vector holding the entire array.
A={1,2,4,5,7,9}
For example, if I pass L=2, R=4, K=2 then it will return the index=3 (indexes start from 1).
In other words, from index 1 to 3 in the vector we are checking from L up to R whichever element is divisible by K. We go forward until an element in this sequence fails to fulfill the divisibility criteria. We then print its ending index. Otherwise, if no such element fulfills the criteria, we return -1
It is a very bad design of the function that does not follow the C++ concepts.
For starters indices in C++ starts from 0. Secondly a range is specified as [start, end) that is end is not included in the range.
The function should return an object of the type std::vector<long long>::size_type. If an element that satisfies the condition is not found in the range then the function should return the value of end.
I would write the function the following way as it is shown in the demonstrative program
#include <iostream>
#include <vector>
#include <algorithm>
auto solve( const std::vector<long long> &v,
std::vector<long long>::size_type first,
std::vector<long long>::size_type last,
long long value )
{
last = std::min( last, v.size() );
first = std::min( first, last );
auto current = first;
while ( ( current != last ) && ( v[current] % value == 0 ) ) ++current;
return current == first ? last : current - 1;
}
int main()
{
using size_type = std::vector<long long>::size_type;
std::vector<long long> v = { 1, 2, 4, 5, 7, 9 };
size_type first = 1;
size_type last = 3;
long long divisor = 2;
auto i = solve( v, first, last, divisor );
if ( i != last )
{
std::cout << "The last element divisible by " << divisor
<< " in the range [" << first
<< ", " << last
<< ") is at position " << i << '\n';
}
else
{
std::cout << "There is no element divisible by " << divisor
<< " in the range [" << first
<< ", " << last << ")\n";
}
}
Its output is
The last element divisible by 2 in the range [1, 3) is at position 2
You could write the same function using iterators. In this case the function declaration would look simpler.
For example
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
auto solve( std::vector<long long>::const_iterator first,
std::vector<long long>::const_iterator last,
long long value )
{
auto it = std::find_if_not( first, last,
[&value]( const long long &item ) { return item % value != 0; } );
return it == first ? last : std::prev( first );
}
int main()
{
std::vector<long long> v = { 1, 2, 4, 5, 7, 9 };
auto first = std::next( std::cbegin( v ), 1 );
auto last = std::next( std::cbegin( v ), 3 );
long long divisor = 2;
auto it = solve( first, last, divisor );
if ( it != last )
{
std::cout << "The last element divisible by " << divisor
<< " in the range [" << std::distance( std::cbegin( v ), first )
<< ", " << std::distance( std::cbegin( v ), last )
<< ") is at position " << std::distance( std::cbegin( v ), it ) << '\n';
}
else
{
std::cout << "There is no element divisible by " << divisor
<< " in the range [" << std::distance( std::cbegin( v ), first )
<< ", " << std::distance( std::cbegin( v ), last ) << ")\n";
}
}
Your logic is flawed as it doesn't break out of the loop on the else case. Rather than work on fixing that I'd suggest moving to using standard algorithms rather than writing your own, for example:
const auto start = next(cbegin(A), L - 1);
const long long finish = distance(start, find_if(start, next(cbegin(A), R - 1), bind(modulus<int>(), placeholders::_1, K)));
const auto result = finish == 0 ? -1 : finish;
As is mentioned by Vlad from Moscow your 1-based indexing increases the complexity. If you were willing to use 0-based indexing, go to a 0 return instead of -1, and use a lambda you could just do:
const auto result = count_if(next(cbegin(A), L), next(cbegin(A), R), [=](const auto i) { return i % K == 0; })
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.
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;