so I know that there are a lot of ways to compute unique permutations.
Usually it is slower to apply restrictions during the generation than removing them afterwards.
So let's say I have a vector of 10 elements.
For the sake of an example:
std::vector<int> v = {7, 5, 16, 8, 5, 8, 1, 7, 3, 25, 109, 8};
I have the unique restriction that I know that I am not allowed to have the same three numbers in a row, so all permutations containing {8,8,8} in any place would be invalid.
In case I have a giant array of e.g. 20 elements I would assume that I could save a lot of time if I skip all permutations that start with {8,8,8}.
Is there any to do anything like this efficiently? How do I figure out at which point it makes sense to add the additional slowdown of checking each permutation?
With your restriction, while iterating in order, it is possible to skip the block of invalid permutations, from the first invalid one.
The first invalid permutation from number of the form
y y y 8 8 x x 8 x
is
y y y 8 8 8 x1 x2 x3 with x1 < x2 < x3.
so you can go directly to last invalid permutation with
y y y 8 8 8 x3 x2 x1 with x1 < x2 < x3.
so just reverse the last numbers.
bool is_valid(const std::vector<int>& v)
{
auto it = std::find(v.begin(), v.end(), 8);
return v.end() - it >= 3 && (*it != *(it + 1) || *it != *(it + 2));
}
void go_to_last_invalid(std::vector<int>& v)
{
auto it = std::find(v.begin(), v.end(), 8);
std::reverse(it + 3, v.end());
}
int main()
{
std::vector<int> v = {1, 7, 7, 8, 8, 8, 9, 10};
do {
if (!is_valid(v)) { go_to_last_invalid(v); continue; }
for (auto e : v) { std::cout << e << " "; } std::cout << std::endl;
} while (std::next_permutation(v.begin(), v.end()));
}
Demo
Related
I have std::set<std::pair<int, int>> intervals which it's values are some intervals, it is somthing similar to this:
{ 0, 5 },
{ 5, 8 },
{ 8, 10 }
and I have a number x can I find in which interval it is using lower_bound or upper_bound?
I need a solution with O(log(N)) complexity.
Because I remember that I saw someone doing it someway like this:
int x;
std::set<std::pair<int, int>> intervals;
cin >> x;
auto ans = intervals.upper_bound({ x, INF })
and I don't remember what was the value of INF
Note: the intervals aren't intersecting.
First of all, if you want to have a set of continuous ranges, you should simply represent them as a set that keeps only the beginning of each range.
set<int> boundaries { 0, 5, 8, 10 };
If you really want to use a structure that keeps both ends of a range, the following will allow you to search in O(log(N)). In the case of keeping both ends, it is possible to express other than continuous ranges set, so this example intentionally omits [6, 8). If the structure keeps both ends, it is also possible to express overlapping ranges set. In that case, we would have to search for more than one range. I left that example out.
#include <algorithm>
#include <limits>
#include <numeric>
#include <set>
using namespace std;
int main()
{
set<pair<int, int>> intervals{ { 0, 5 },
{ 5, 6 },
{ 8, 10 } }; // drop {6, 8} version.
{
constexpr auto INF = numeric_limits<int>::max();
auto find = [&](const int x) {
auto next = intervals.upper_bound({ x, INF });
if (next != intervals.begin()) {
if (auto ans = prev(next); x < ans->second)
return ans;
}
return intervals.end();
};
for (int x = -1; x <= 11; ++x) {
if (auto ans = find(x); ans != intervals.end()) {
printf("%d is in [%d, %d)\n", x, ans->first, ans->second);
} else {
printf("%d is not in any range\n", x);
}
}
}
set<int> boundaries{ 0, 5, 8, 10 };
{
auto find = [&](const int x) {
auto next = boundaries.upper_bound(x);
if (next != boundaries.begin()) {
return prev(next);
}
return boundaries.end();
};
for (int x = -1; x <= 11; ++x) {
if (auto ans = find(x); ans != boundaries.end()) {
if (auto nx = next(ans); nx != boundaries.end()) {
printf("%d is in [%d, %d)\n", x, *ans, *nx);
} else {
printf("%d is in [%d, inf)\n", x, *ans);
}
} else {
printf("%d is in [-inf, %d)\n", x, *boundaries.begin());
}
}
}
}
stdout is here.
// == set<pair<int, int>>
-1 is not in any range
0 is in [0, 5)
1 is in [0, 5)
2 is in [0, 5)
3 is in [0, 5)
4 is in [0, 5)
5 is in [5, 6)
6 is not in any range
7 is not in any range
8 is in [8, 10)
9 is in [8, 10)
10 is not in any range
11 is not in any range
// == set<int>
-1 is in [-inf, 0)
0 is in [0, 5)
1 is in [0, 5)
2 is in [0, 5)
3 is in [0, 5)
4 is in [0, 5)
5 is in [5, 8)
6 is in [5, 8)
7 is in [5, 8)
8 is in [8, 10)
9 is in [8, 10)
10 is in [10, inf)
11 is in [10, inf)
I have two vectors
vector<int> first_v = {1, 4, 9, 16, 8, 56};
vector<int> second_v = {20, 30};
And the goal is to combine those vectors in specific order like that (basically program first prints one value of the first_v vector and then one value of second_v vector):
Expected Output:
1 20 4 30 9 16 8 56
I'm very close to solution but the problem is that if one vector is shorter than another, then program will print '0'.
Problem output:
1 20 4 30 9 0 16 0
Here is the code I tried to solve this problem
merge_vect(first_v, second_v);
vector<int> merge_vect(const vector<int> & a, const vector<int> & b){
vector<int> vec(a.size() + b.size());
for (int i = 0; i < vec.size(); i++){
cout << a[i] << " ";
cout << b[i] << " ";
}
return vec;
}
What can I do in order to solve this problem?
You could keep one iterator to each vector and add from the vector(s) that have not reached their end() iterator.
Example:
#include <iostream>
#include <vector>
std::vector<int> merge_vect(const std::vector<int>& avec,
const std::vector<int>& bvec)
{
std::vector<int> result;
result.reserve(avec.size() + bvec.size());
for(auto ait = avec.begin(), bit = bvec.begin();
ait != avec.end() || bit != bvec.end();)
{
if(ait != avec.end()) result.push_back(*ait++);
if(bit != bvec.end()) result.push_back(*bit++);
}
return result;
}
int main() {
std::vector<int> first_v = {1, 4, 9, 16, 8, 56};
std::vector<int> second_v = {20, 30};
auto result = merge_vect(first_v, second_v);
for(auto val : result) std::cout << val << ' ';
}
Output:
1 20 4 30 9 16 8 56
A possible optimization could copy from both vectors for as long as both have elements and then copy the rest from the larger vector in one go:
std::vector<int> merge_vect(const std::vector<int>& avec,
const std::vector<int>& bvec)
{
std::vector<int> result;
result.reserve(avec.size() + bvec.size());
auto ait = avec.begin(), bit = bvec.begin();
// copy while both have more elements:
for(; ait != avec.end() && bit != bvec.end(); ++ait, ++bit) {
result.push_back(*ait);
result.push_back(*bit);
}
// copy the rest
if(ait != avec.end()) result.insert(result.end(), ait, avec.end());
else if(bit != bvec.end()) result.insert(result.end(), bit, bvec.end());
return result;
}
So let's assume I have an array array{12, 10, 10, 9, 8, 8, 8} in descending order.
I want to sort the numbers that can be divided by 2 but not with 4 in ascending order at the end of the array, the numbers that are divided by 4 sorted at the start of the array in descending order and the rest in the middle(no specific order). For my example, after the transformation it should look something like this:
array{12, 8, 8, 8, 9, 10, 10}. Is there any way I can do this efficiently? c++ language.
Sorry for any misspelling.
Let's organize the requirement.
The required order is:
Numbers that are divided by 4
Others
Numbers that can be divided by 2 but not with 4
Among the numbers with same priority according to the above rule, the numbers should be
Descending order
No specific order
Ascending order
Let's implement this:
#include <iostream>
#include <vector>
#include <algorithm>
void test(std::vector<int> array) { // intensionally passed by value
std::cout << "before sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
std::sort(array.begin(), array.end(), [](int a, int b) -> bool {
int pa, pb; // priority a/b
if (a % 4 == 0) pa = 1;
else if (a % 2 == 0) pa = 3;
else pa = 2;
if (b % 4 == 0) pb = 1;
else if (b % 2 == 0) pb = 3;
else pb = 2;
// if the priority differs, sort according to the priority
if (pa != pb) return pa < pb;
// if both can be divided by 4, sort in descending order
if (pa == 1) return b < a;
// if both can be divided by 2 but not with 4, sort in ascending order
if (pa == 3) return a < b;
// no specific order for the rest
return false;
});
std::cout << "after sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
}
int main(void) {
std::vector<int> array = {12, 10, 10, 9, 8, 8, 8};
std::vector<int> array2 = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
test(array);
std::cout << '\n';
test(array2);
return 0;
}
Example output:
before sorting: 12 10 10 9 8 8 8
after sorting: 12 8 8 8 9 10 10
before sorting: 10 9 8 7 6 5 4 3 2 1
after sorting: 8 4 9 7 5 3 1 2 6 10
As an alternative to MikeCAT's fine answer, C++20 adds a variation of sort which accepts a projection, i.e. a function to apply to each element before we pass it to the comparison functor.
This utilises the fact that std::tuple has a predefined < that orders the tuple by each member in turn.
#include <iostream>
#include <vector>
#include <algorithm>
std::tuple<int, int> my_order(int val) {
if (val % 4 == 0) return { 1, -val };
else if (val % 2 == 0) return { 3, val };
else return { 2, 0 };
}
void test(std::vector<int> array) { // intensionally passed by value
std::cout << "before sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
std::ranges::sort(array.begin(), array.end(), std::ranges::less{}, my_order);
std::cout << "after sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
}
int main(void) {
std::vector<int> array = {12, 10, 10, 9, 8, 8, 8};
std::vector<int> array2 = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
test(array);
std::cout << '\n';
test(array2);
return 0;
}
I'm trying to debug this program to find the number of matching elements that occur at the same index in 2 different vectors. Requirement is to NOT use any loops
Code on online compiler: http://cpp.sh/8rvtj
#include <iostream>
#include <vector>
using namespace std;
int calls=0;
int matchCount(const vector<int>& v1, const vector<int>& v2, int i=0)
{
calls++;
static int smallVecSz=-1;
smallVecSz = (v1.size()<v2.size() ? v1.size() : v2.size());
static int ans=0;
if(i==smallVecSz)
{
cout << "Returning " << ans << endl;
return ans;
}
// if element at index i is same in v1 and v2, add 1 to ans else add 0 to ans
ans += (v1[i]==v2[i] ? 1 : 0);
return ans + matchCount(v1,v2,i+1); // pass optional param index i+1 to advance to next ele
}
int main()
{
vector<int> v1 = {2, 5, 2, 1, 8, 9, 1, 6, 9, 2};
vector<int> v2 = {2, 5, 3, 0, 8, 4, 1};
cout << "There are " << matchCount(v1,v2) << " matching numbers at same indexes" << endl;
cout << "Number of Recursion calls: " << calls << endl;
return 0;
}
Here is a sample input:
vector v1 = {2, 5, 2, 1, 8, 9, 1, 6, 9, 2};
vector v2 = {2, 5, 3, 0, 8, 4, 1};
Here is a sample output:
Returning 4
There are 32 matching numbers at same indexes
Number of Recursion calls: 8
My program is recursive function is correctly returning the ans 4. But the main program is printing 32.
Oops, a static variable accumulating in a recursive function is a code smell.
Normally, when you use recursion, each call starts with a clean an fresh environment.
In that case, you accumulate the value of each call with its children to find the total.
Alternatively, you can use a static variable which is updated by each call and just used by the top parent.
But here you are mixing both approaches, actually getting a much too high value.
So 2 ways here:
make ans an automatic (non static) variable:
...
smallVecSz = (v1.size()<v2.size() ? v1.size() : v2.size());
int ans=0;
if(i==smallVecSz)
...
keep ans static, and do not accumulate:
...
ans += (v1[i]==v2[i] ? 1 : 0);
matchCount(v1, v2, i+1); // pass optional param index i+1 to advance to next ele
return ans;
...
Of course in that case, you will get wrong results if you call the function more than once because ans will not be reset to 0 (Thanks to #bruno for noticing)
your problem comes from ans being static and the fact you return it when you reach the end of the vector rather than 0 etc
I do not understand too why that function is recursive
a solution with a loop and an other with recursion as you requested in a comment
#include <iostream>
#include <vector>
using namespace std;
int matchCount(const vector<int>& v1, const vector<int>& v2)
{
vector<int>::const_iterator it1;
vector<int>::const_iterator it2;
int result = 0;
for (it1 = v1.begin(), it2 = v2.begin();
(it1 != v1.end()) && (it2 != v2.end());
++it1, ++it2) {
if (*it1 == *it2)
result += 1;
}
return result;
}
int recurMatchCount(const vector<int>& v1, const vector<int>& v2, int i = 0)
{
return ((i == v1.size()) || (i == v2.size()))
? 0
: (((v1[i] == v2[i]) ? 1 : 0)
+ recurMatchCount(v1, v2, i + 1));
}
int main()
{
vector<int> v1 = {2, 5, 2, 1, 8, 9, 1, 6, 9, 2};
vector<int> v2 = {2, 5, 3, 0, 8, 4, 1};
cout << "There are " << matchCount(v1,v2) << " matching numbers at same indexes" << endl;
cout << "There are " << recurMatchCount(v1,v2) << " recur matching numbers at same indexes" << endl;
return 0;
}
How is the y.size() = 4 in the following? The values in y are {11, 2, 4, 7} How does one arrive at this? What are a and b in the operator() function for each iteration of the set. I don't understand the construction of y and I can't find anything online that explains this situation. Thank You
#include <iostream>
#include <set>
struct C
{
bool operator()(const int &a, const int &b) const
{
return a % 10 < b % 10;
}
};
int main()
{
std::set<int> x({ 4, 2, 7, 11, 12, 14, 17, 2 });
std::cout << x.size() << std::endl;
std::set<int, C> y(x.begin(), x.end());
std::cout << y.size() << std::endl;
std::set<int>::iterator iter;
for (iter = y.begin(); iter != y.end(); ++iter)
{
std::cout << *iter << std::endl;
}
return 0;
}
Second template argument of set is comparator type — type of functor that implements less operation.
struct C
{
bool operator()(const int &a, const int &b) const
{
return a % 10 < b % 10;
}
};
This comparator will compare a and b as a < b only if a % 10 < b % 10, so practically all numbers will be compared by modulo 10.
UPDATE:
After pushing into x set numbers { 4, 2, 7, 11, 12, 14, 17, 2 }, set will contain seven elements { 2, 4, 7, 11, 12, 14, 17 }. These elements will be sorted in that way, because set stores objects in sorted way.
Then numbers from x set are being sequentially inserted into y set. Before inserting of each element, set will find proper place in sorted order of currently inserted numbers. If set will see, that there is already some number on it's place, set will not insert it.
After inserting {2, 4, 7} from x to y, y will be {2, 4, 7}.
Then, to insert 11 into y set will do comparisons of 11 with {2, 4, 7} to find proper place using provided C functor.
To check is 11 less than 2 set will call C()(11, 2), which will result in 11 % 10 < 2 % 10 comparison, which will result in true, so 11 will be inserted before 2.
Other numbers from x (12, 14, 17) will not be inserted, because set will find, that 12 should be on place of 2 (because 2 % 10 < 12 % 10 or 12 % 10 < 2 % 10 expression is false, so 2 == 12), and in same way 14 and 17.