I have an array of pairs that represent a range of [begin,end). The array can be assumed to already sorted by the 'begin' field.
I want to generate a new array with all of the overlaps removed, and additional pairs created, as needed.
For example, let's say the array contained the following pairs:
[1,3],[2,5],[7,15],[8,9],[12,19]
The output should be as follows:
[1,2],[2,3],[3,5],[7,8],[8,9],[9,12],[12,15],[15,19]
Ultimately, the output array should contain no overlaps at all.
What's the most optimal solution that takes no more than O(m), where m is the number of entries needed in the output array? I think I see a way to do it in O(n^2), where n is the number of entries in the input array, but there's got to be a better way.
The final implementation will be in C++11, using vectors of pairs of doubles, although pseudocode solutions are fine.
EDIT:
I appreciate all responses, but I would politely request in advance to please not post any solutions that depend on particular frameworks or libraries unless such frameworks are part of standard c++11.
First I'll solve a related problem; generate merged intervals that cover the same area with no adjacency or overlap.
Walk the input array. Start with the first element. Record highwater (end of interval) and lowater (start of interval).
Proceed forward. Each element, if it overlaps the interval, extend highwater. If not, output highwater and lowater as an interval, then record a new high and lowater.
This takes O(n) time on input.
Every element of input must be read, because any of them could go from their start location to the end and change the result. So this is O-optimal.
This merges intervals into the largest contiguous one you can make; you want to save all of the "edges" or "seams" in the original intervals. To solve your spec, simply keep track of seams (in order) and break the generated intervals at those seams. "Lowater" seams will always come with increasing values; highwater seams may not. So an ordered set of seams should work. This is O(nlgn) sadly due to the set.
// half open
struct interval {
int lowater = 0;
int highwater = 0;
bool empty() const {
return lowater == highwater;
}
friend std::ostream& operator<<( std::ostream& os, interval i ) {
return os << "[" << i.lowater << "," << i.highwater << "]";
}
};
template<class Range, class Out>
void build_intervals( Range&& in, Out out ) {
std::optional<interval> current;
std::set<int> seams;
auto dump_interval = [&](interval i){
if (i.empty()) return;
*out = i;
};
auto dump_current = [&]{
if (!current) return;
// std::cout << "Dumping " << *current << " with seams: {";
for (int seam:seams) {
// std::cout << seam << ",";
dump_interval({ current->lowater, seam });
current->lowater = seam;
}
// std::cout << "}\n";
dump_interval( *current );
current = std::nullopt;
seams.clear();
};
for (auto&& e : in) {
if (current && e.lowater <= current->highwater) {
seams.insert(e.lowater);
seams.insert(e.highwater);
// std::cout << "No gap between " << *current << " and " << e << "\n";
current->highwater = (std::max)(e.highwater, current->highwater);
// std::cout << "Combined: " << *current << "\n";
continue;
}
if (!current) {
// std::cout << "New current " << e << "\n";
} else {
// std::cout << "Gap between " << *current << " and " << e << "\n";
dump_current();
}
current = e;
seams.insert(e.lowater);
seams.insert(e.highwater);
}
dump_current();
}
live example.
I came up with something like this, by adding just couple of if it is done in O(n) time. I'm just not sure about last elements, my output:
[1 : 2], [2 : 3], [3 : 5], [7 : 8], [8 : 9], [9 : 12], [12 : 15], [15 : 19]
Maybe its something that would help:
std::vector<std::pair<int, int>> noOverlaps(std::vector<std::pair<int, int>>& input) {
if (input.size() <= 1) {
return input;
}
std::vector<std::pair<int, int>> result;
result.push_back(input[0]);
for (int i = 1; i < input.size(); ++i) {
//If overlap
if (input[i].first < result.back().second) {
auto lastOne = result.back();
result.pop_back();
result.push_back(std::make_pair(lastOne.first, input[i].first));
if (lastOne.second > input[i].second) {
result.push_back(std::make_pair(input[i].first, input[i].second));
result.push_back(std::make_pair(input[i].second, lastOne.second));
} else {
result.push_back(std::make_pair(input[i].first, lastOne.second));
result.push_back(std::make_pair(lastOne.second, input[i].second));
}
} else {
result.push_back(input[i]);
}
}
return result;
}
Update 1
As pointed out in the comment above will not work with multiple overlapping intervals, so the above solution can be improved by swallowing intervals that are containing each other and run the same algorithm:
std::vector<std::pair<int, int>> noOverlaps(std::vector<std::pair<int, int>>& origInput) {
if (origInput.size() <= 1) {
return origInput;
}
std::vector<std::pair<int, int>> result;
std::vector<std::pair<int, int>> input;
input.push_back(origInput[0]);
for (int i = 1; i < origInput.size(); ++i) {
if (input[i-1].first <= origInput[i].first && input[i-1].second >= origInput[i].second) {
continue;
}
input.push_back(origInput[i]);
}
result.push_back(input[0]);
for (int i = 1; i < input.size(); ++i) {
//If overlap
if (input[i].first < result.back().second) {
auto lastOne = result.back();
result.pop_back();
result.push_back(std::make_pair(lastOne.first, input[i].first));
if (lastOne.second > input[i].second) {
result.push_back(std::make_pair(input[i].first, input[i].second));
result.push_back(std::make_pair(input[i].second, lastOne.second));
} else {
result.push_back(std::make_pair(input[i].first, lastOne.second));
result.push_back(std::make_pair(lastOne.second, input[i].second));
}
} else {
result.push_back(input[i]);
}
}
return result;
}
But this requires 2xO(n) space complexity and code is not nice.
So I just wonder would that not be enough:
std::vector<std::pair<int, int>> noOverlaps2(std::vector<std::pair<int, int>>& origInput) {
if (origInput.size() <= 1) {
return origInput;
}
int low = origInput[0].first, high = origInput[0].second;
std::vector<std::pair<int, int>> result;
for (int i = 1; i < origInput.size(); ++i) {
if (high < origInput[i].first) {
result.emplace_back(low, high);
low = origInput[i].first;
high = origInput[i].second;
} else {
high = std::max(origInput[i].second, high);
}
}
result.emplace_back(low, high);
return result;
}
For your data it gives output:[1 : 5], [7 : 19] but it get rid of overlaps.
Related
I try to implement Hierholzer's algorithm in C++. The underlying multigraph is represented using a two-dimensional map, which maps two vertices to the number of edges between them. My approach is to decrement this count of an edge every time it is traversed and completely removing it if the count is 0.
This is the function:
vector<int> euler_tour(map_2d edge_copies) {
map<int, int> available_nodes;
available_nodes.insert({ 0, 0 });
vector<int> tour = { 0 };
while (!edge_copies.empty()) {
int n0 = (available_nodes.begin())->first;
int n = n0;
vector<int> subtour = { n0 };
while (!edge_copies.at(n).empty()) {
int n_ = (edge_copies.at(n).begin())->first;
subtour.push_back(n_);
cout << n << " " << n_ << endl;
cout << "graph and soubtour: " << endl;
print_map_2d(edge_copies);
print_vector(subtour);
edge_copies.at(n).at(n_) -= 1;
edge_copies.at(n_).at(n) -= 1;
if (edge_copies.at(n).at(n_) == 0) {
edge_copies.at(n).erase(n_);
edge_copies.at(n_).erase(n);
}
if (edge_copies.at(n).empty()) {
edge_copies.erase(n);
available_nodes.erase(n);
} else {
available_nodes[n] = available_nodes.at(n0) + subtour.size() - 1;
}
if (edge_copies.at(n_).empty()) {
edge_copies.erase(n_);
available_nodes.erase(n_);
} else {
available_nodes[n_] = available_nodes.at(n0) + subtour.size();
}
n = n_;
}
tour.insert(tour.begin() + available_nodes[n0], subtour.begin(), subtour.end());
print_vector(tour);
}
}
When I execute it, i get munmap_chunk(): invalid pointer after the first iteration of the second while loop. I experimented a bit, and I think it breaks at the line subtour.push_back(n_);. But why? This is a standard operation. Or do you see any other problematic lines?
The functions print_map_2d and print_vector are implemented elsewhere, they are surely not the problem.
Need to move all values which is less than 1 in begin of array (WITHOUT SORT, and need solution without second array)
for example:
START ARRAY: {-2.12, -3, 7.36, 6.83, -1.82, 7.01}
FINISH ARRAY: {-2.12, -3, -1.82, 7.36, 6.83, 7.01}
There is my solution but it doesn't work very well, because at final we receive:
FINISH ARRAY: {-2.12, -3, -1.82, 6.83, 7.36, 7.01}
Values which less than 1, moves to begin of array, but 4 and 5 elements not in correct order
#include <iostream>
using namespace std;
int main() {
double arr[6] = {-2.12, -3, 7.36, 6.83, -1.82, 7.01};
cout << "Start array: " << endl;
for (int x = 0; x < 6; x++) {
cout << arr[x] << ", ";
}
int index=0;
double temp;
for (int i = 0; i < 6; i++) {
if (arr[i] < 1) {
temp=arr[i];
arr[i] = arr[index];
arr[index] = temp;
index++;
}
}
cout << endl << "FINISH ARRAY: " << endl;
for (int x = 0; x < 6; x++) {
cout << arr[x] << ", ";
}
return 0;
}
Use std::stable_partition:
std::stable_partition(std::begin(arr), std::end(arr),
[](double d) { return d < 1; });
If you want to implement it yourself, note, that in-place stable partition (using comparisons and swaps) cannot be done better than in O(N log N) time. Any algorithm with O(N) running time is incorrect.
One possible solution can be obtained with divide-and-conquer approach:
template<class It, class Pred>
It stable_partition(It first, It last, Pred pred) {
// returns the iterator to the first element of the second group:
// TTTTTFFFFFF
// ^ return value
if (first == last)
return last;
if (last - first == 1) {
if (pred(*first)) // T
return last; // ^ last
else // F
return first; // ^ first
}
// Split in two halves
const auto mid = first + (last - first) / 2;
// Partition the left half
const auto left = stable_partition(first, mid, pred);
// TTTTTFFFFF
// ^ left
// ^ mid
// Partition the right half
const auto right = stable_partition(mid, last, pred);
// TTTTTFFFFF
// ^ right
// ^ mid
// Rotate the middle part: TTTTTFFFFFTTTTTFFFFF
// ~~~~~~~~~~
// ^ left ^ right
// ^ mid
const auto it = std::rotate(left, mid, right);
// TTTTTTTTTTFFFFFFFFFF
// ^ it
return it;
}
It resembles quicksort, but here we do not actually sort the range. std::rotate itself can be easily implemented via three reverses.
Let say I've a target number and a list of possibile values that I can pick to create a sequence that, once summed every picked number, will sum to the target:
target = 31
list = 2, 3, 4
possible sequence: 3 2 4 2 2 2 4 2 3 2 3 2
I'd like to:
first decide if there is any sequence that will reach the target
return one of the many (possible) sequence
This is my attempt:
#include <iostream>
#include <random>
#include <chrono>
#include <vector>
inline int GetRandomInt(int min = 0, int max = 1) {
uint64_t timeSeed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
std::seed_seq ss{ uint32_t(timeSeed & 0xffffffff), uint32_t(timeSeed >> 32) };
std::mt19937_64 rng;
rng.seed(ss);
std::uniform_int_distribution<int> unif(min, max);
return unif(rng);
}
void CreateSequence(int target, std::vector<int> &availableNumbers) {
int numAttempts = 1;
int count = 0;
std::vector<int> elements;
while (count != target) {
while (count < target) {
int elem = availableNumbers[GetRandomInt(0, availableNumbers.size() - 1)];
count += elem;
elements.push_back(elem);
}
if (count != target) {
numAttempts++;
count = 0;
elements.clear();
}
}
int size = elements.size();
std::cout << "count: " << count << " | " << "num elements: " << size << " | " << "num attempts: " << numAttempts << std::endl;
for (auto it = elements.begin(); it != elements.end(); it++) {
std::cout << *it << " ";
}
}
int main() {
std::vector<int> availableNumbers = { 2, 3, 4 };
CreateSequence(31, availableNumbers);
}
But it can loop infinitely if the list of number can't be appropriate to reach such sum; example:
std::vector<int> availableNumbers = { 3 };
CreateSequence(8, availableNumbers);
No sequence of 3 will sum to 8. Also, if the list is huge and the target number high, it can lead to a huge amount of processing (cause lots of while check fails).
How would you implement this kind of algorithm?
Your suggested code is possibly very fast, since it is heuristic. But as you said, it gets potentially trapped in a nearly endless loop.
If you want to avoid this situation, you have to search the complete set of possible combinations.
Abstraction
Let's define our algorithm as a function f with a scalar target t and a vector <b> as parameters returning a vector of coefficients <c>, where <b> and <c> have the same dimension:
<c> = f(t, <b>)
First the given set of numbers Sg should be reduced to their reduced set Sr so we reduce the dimension of our solution vector <c>. E.g. {2,3,4,11} can be reduced to {2,3}. We get this by calling our algorithm recursively by splitting Sg into a new target ti with the remaining numbers as the new given set Sgi and ask the algorithm, if it finds any solution (a non-zero vector). If so, remove that target ti from the original given set Sg. Repeat this recursively until no solutions found any more.
Now we can understand this set of numbers as a polynomial, where we are looking for possible coefficients ci to get our target t. Let's call each element in Sb bi with i={1..n}.
Our test sum ts is the sum over all i for ci * bi, where each ci can run from 0 to ni = floor(t/bi).
The number of possible tests N is now the product over all ni+1: N = (n1+1) * (n2+1) * ... * (ni+1).
Iterate now over all possibilities by representing the coefficient vector <c> as an vector of integers and incrementing c1 and carrying over an overrun to the next element in the vector, resetting c1 and so forth.
Example
#include <random>
#include <chrono>
#include <vector>
#include <iostream>
using namespace std;
static int evaluatePolynomial(const vector<int> &base, const vector<int> &coefficients)
{
int v=0;
for(unsigned long i=0; i<base.size(); i++){
v += base[i]*coefficients[i];
}
return v;
}
static bool isZeroVector(vector<int> &v)
{
for (auto it = v.begin(); it != v.end(); it++) {
if(*it != 0){
return false;
}
}
return true;
}
static vector<int> searchCoeffs(int target, vector<int> &set) {
// TODO: reduce given set
vector<int> n = set;
vector<int> c = vector<int>(set.size(), 0);
for(unsigned long int i=0; i<set.size(); i++){
n[i] = target/set[i];
}
c[0] = 1;
bool overflow = false;
while(!overflow){
if(evaluatePolynomial(set, c) == target){
return c;
}
// increment coefficient vector
overflow = true;
for(unsigned long int i=0; i<c.size(); i++){
c[i]++;
if(c[i] > n[i]){
c[i] = 0;
}else{
overflow = false;
break;
}
}
}
return vector<int>(set.size(), 0);
}
static void print(int target, vector<int> &set, vector<int> &c)
{
for(unsigned long i=0; i<set.size(); i++){
for(int j=0; j<c[i]; j++){
cout << set[i] << " ";
}
}
cout << endl;
cout << target << " = ";
for(unsigned long i=0; i<set.size(); i++){
cout << " +" << set[i] << "*" << c[i];
}
cout << endl;
}
int main() {
vector<int> set = {4,3,2};
int target = 31;
auto c = searchCoeffs(target, set);
print(target, set,c);
}
That code prints
4 4 4 4 4 4 4 3
31 = +4*7 +3*1 +2*0
Further Thoughts
productive code should test for zeros in any given values
the search could be improved by incrementing the next coefficient if the evaluated polynomial already exceeded the target value.
further speedup is possible, when calculating the difference of the target value and the evaluated polynomial when c1 is set to zero, and checking if that difference is a multiple of b1. If not, c2 could be incremented straight forward.
Perhaps there exist some shortcuts exploiting the least common multiple
As ihavenoidea proposed, I would also try backtracking. In addition, I will sort the numbers in decreasing order, il order to speed up the process.
Note: a comment would be more appropriate than an answer, but I am not allowed to. Hope it helps. I will suppress this answer if requested.
I need an algorithm that, given an even number of elements, performs an evaluation on all combinations of the elements divided into two groups. Order within a group doesn't matter and so permutations within groups shouldn't be repeated. An example with N=4 elements would be the evaluations
e(12,34), e(13,24), e(14,32), e(32,14), e(34,12), e(24,13)
I thought I had it, with a recursive algorithm that works up to N=6, but it turns out it fails for N=8. This is the algorithm (this version just prints out the two groups; in my actual implementation it will perform a calculation):
// Class for testing algoritm
class sym {
private:
int N, Nhalf, combs;
VI order;
void evaluate();
void flip(int, int);
void combinations(int, int);
public:
void combinations();
sym(int N_) : N(N_) {
if(N%2) {
cout "Number of particles must divide the 2 groups; requested N = " << N << endl;
throw exception();
}
Nhalf=N/2;
order.resize(N);
for(int i=0;i<N;i++) order[i]=i+1;
}
~sym() {
cout << endl << combs << " combinations" << endl << endl;
}
};
// Swaps element n in group 1 and i in group 2
void sym::flip(int n, int i) {
int tmp=order[n];
order[n]=order[i+Nhalf];
order[i+Nhalf]=tmp;
}
// Evaluation (just prints the two groups)
void sym::evaluate() {
for(int i=0;i<Nhalf;i++) cout << order[i] << " ";
cout << endl;
for(int i=Nhalf;i<N;i++) cout << order[i] << " ";
cout << endl << "--------------------" << endl;
combs++;
}
// Starts the algorithm
void sym::combinations() {
cout << "--------------------" << endl;
combinations(0, 0);
}
// Recursive algorithm for the combinations
void sym::combinations(int n, int k) {
if(n==Nhalf-1) {
evaluate();
for(int i=k;i<Nhalf;i++) {
flip(n, i);
evaluate();
flip(n, i);
}
return;
}
combinations(n+1, k);
for(int i=k;i<Nhalf;i++) {
flip(n, i);
combinations(n+1, k+i+1);
flip(n, i);
}
}
If I run this with N=2 for example, I get the correct
--------------------
1 2
3 4
--------------------
1 3
2 4
--------------------
1 4
3 2
--------------------
3 2
1 4
--------------------
3 4
1 2
--------------------
4 2
3 1
--------------------
6 combinations
But it seems N>6 doesn't work. Is there a simple change that will fix this, or will I have to rethink the whole thing?
EDIT: It is better if every change just involves swapping two elements (like the failed attempt above); as this will make the code faster in the end I think.
EDIT: Just realised it fails for N=6 as well, sloppy testing.
std::next_permutation may help (without recursion):
#include <iostream>
#include <algorithm>
template<typename T>
void do_job(const std::vector<T>& v, const std::vector<std::size_t>& groups)
{
std::cout << " e(";
for (std::size_t i = 0; i != v.size(); ++i) {
if (groups[i] == 0) {
std::cout << " " << v[i];
}
}
std::cout << ",";
for (std::size_t i = 0; i != v.size(); ++i) {
if (groups[i] == 1) {
std::cout << " " << v[i];
}
}
std::cout << ")\n";
}
template<typename T>
void print_combinations(const std::vector<T>& v)
{
std::vector<std::size_t> groups(v.size() / 2, 0);
groups.resize(v.size(), 1); // groups is now {0, .., 0, 1, .., 1}
do {
do_job(v, groups);
} while (std::next_permutation(groups.begin(), groups.end()));
}
int main()
{
std::vector<int> numbers = {1, 2, 3, 4};
print_combinations(numbers);
}
Live Demo
// generate all combination that use n of the numbers 1..k
void sym::combinations(int n, int k) {
if (n>k) return; // oops
if (n==0) { evaluate(); return; }
combinations(n, k-1);
order[n-1] = k;
combinations(n-1,k-1);
}
Start that with combinations(N/2,N) No need to pre initialize order. But as coded it only fills the first half of order with the first group and you need to post process to get the second group.
With a moderate amount of extra logic, you could instead fill in the second half during combinations. I think this does it:
void sym::combinations(int n, int k) {
if (k==0) { evaluate(); return; }
if (n>0) {
order[n-1] = k;
combinations(n-1,k-1); }
if (n<k) {
order[Nhalf+k-n-1] = k;
combinations(n, k-1); }
}
I think a flip based design is uglier. But after more thought, it isn't actually difficult. So changing back to your design of starting at combinations(0,0) you could use:
// Generate all combinations subject to having already filled the first n
// of the first group and having already filled the last k of the second.
void sym::combinations(int n, int k) {
if(n==Nhalf) {
// Once the first group is full, the rest must be the second group
evaluate();
return;
}
// Since the first group isn't full, recursively get all combinations
// That make the current order[n] part of the first group
combinations(n+1,k);
if (k<Nhalf) {
// Next try all combinations that make the current order[n] part of
// the second group
std::swap(order[n], order[N-k-1]);
combinations(n,k+1);
// Since no one cares about the sequence of the items not yet chosen
// there is no benefit to swapping back.
}
}
To recursively list the n choose n/2 combinations you could use an algorithm that adds each value to either group:
f(n,k,A,B):
if k == 0:
output A,B with {n,n-1..1}
else if n == k:
output A with {n,n-1..1},B
else if k > 0:
f(n-1,k-1,A with n,B)
f(n-1,k,A,B with n)
Example below. To half the accumulating stack, one could skip one of the two first recursive calls and reverse the order of the pair during evaluation.
f(4,2,[],[])
f(3,1,[4],[])
f(2,0,[4,3],[]) => {[4,3],[2,1]}
f(2,1,[4],[3])
f(1,0,[4,2],[3]) => {[4,2],[3,1]}
f(1,1,[4],[3,2]) => {[4,1],[3,2]}
f(3,2,[],[4])
f(2,1,[3],[4])
f(1,0,[3,2],[4]) => {[3,2],[4,1]}
f(1,1,[3],[4,2]) => {[3,1],[4,2]}
f(2,2,[],[4,3]) => {[2,1],[4,3]}
I am trying to calculate the prime numbers using a set but when I do the calculation my iterator is jumping randomly.
I am trying to implement this method for an value of N=10.
Choose an integer n. This function will compute all prime numbers up
to n. First insert all numbers from 1 to n into a set. Then erase all
multiples of 2 (except 2); that is, 4, 6, 8, 10, 12, .... Erase all
multiples of 3, that is, 6, 9, 12, 15, ... . Go up to sqrt(n) . The
remaining numbers are all primes.
When I run my code, it erases 1 and then pos jumps to 4? I am not sure why this happens instead of it going to the value 2 which is the 2nd value in the set?
Also what happens after I erase a value that the iterator is pointing to, what does the iterator point to then and if I advance it where does it advance?
Here is the code:
set<int> sieveofEratosthenes(int n){ //n = 10
set<int> a;
set<int>::iterator pos = a.begin();
//generate set of values 1-10
for (int i = 1; i <= n; i++) {
a.insert(i);
if(pos != a.end())
pos++;
}
pos = a.begin();
//remove prime numbers
while (pos != a.end())
{
cout << "\nNew Iteration \n\n";
for (int i = 1; i < sqrt(n); i++) {
int val = *pos%i;
cout << "Pos = " << *pos << "\n";
cout << "I = " << i << "\n";
cout << *pos << "/" << i << "=" << val << "\n\n";
if (val == 0) {
a.erase(i);
}
}
pos++;
}
return a;
}
Your implementation is incorrect in that it is trying to combine the sieve algorithm with the straightforward algorithm of trying out divisors, and it does so unsuccessfully. You do not need to test divisibility to implement the sieve - in fact, that's a major contributor to the beauty of the algorithm! You do not even need multiplication.
a.erase(1);
pos = a.begin();
while (pos != a.end()) {
int current = *pos++;
// "remove" is the number to remove.
// Start it at twice the current number
int remove = current + current;
while (remove <= n) {
a.erase(remove);
// Add the current number to get the next item to remove
remove += current;
}
}
Demo.
When erasing elements inside a loop you have to be carefull with the indices. For example, when you erase the element at position 0, then the next element is now at position 0. Thus the loop should look something like this:
for (int i = 1; i < sqrt(n); /*no increment*/) {
/* ... */
if (val == 0) {
a.erase(i);
} else {
i++;
}
}
Actually, you also have to take care that the size of the set is shrinking while you erase elements. Thus you better use iterators:
for (auto it = a.begin(); i != a.end(); /*no increment*/) {
/* ... */
if (val == 0) {
a.erase(it);
} else {
it++;
}
}
PS: the above is not exactly what you need for the sieve, but it should be sufficient to demonstrate how to erase elements (I hope so).