The problem:
I have 2 arrays A[v] and M[w], with length v and w, respectively. Given two numbers p and q, I want to find how many combinations of the sum of two elements of these arrays satisfy the following condition:
p >= A[v] + M[w] <= q
An example:
Let:
A = [9, 14, 5, 8, 12, 2, 16],
v = 7,
M = [6, 2, 9, 3, 10],
w = 5,
p = 21,
q = 24
The answer will be 5, because of the following combinations:
14 + 9 = 23
14 + 10 = 24
12 + 9 = 21
12 + 10 = 22
16 + 6 = 22
What I have tried:
The following is an implementation of the problem in C++:
int K = 0; // K is the answer
for (int i=0; i<v; i++) {
for (int j=0; j<w; j++) {
if (A[v]+M[w] >= p && A[v]+M[w] <= q) {
++K;
}
}
}
As we can see the above code uses a loop inside a loop, thus making the time complexity of the program Ο(v×w), pretty slow for large arrays.
The question
Is there a fastest way to solve this problem?
Problem Summary: Given two arrays A and B with sizes v and w respectively, find the number of possible pairings of an element from A and an element from B such that the two elements have a sum that is >= p and <= q.
The simple, brute force algorithm is essentially what you have currently. The brute force algorithm would simply involve testing all possible pairs, which, as you said, would have a time complexity of O(v*w) because there are v ways to choose the first element and w ways to choose the second element when testing all the pairs.
As #thestruggler pointed out in their comment, sorting and binary search could be applied to create a significantly more efficient algorithm.
Let's say we sort B in ascending order. For the test case you provide, we would then have:
A = [9, 14, 5, 8, 12, 2, 16]
B = [2, 3, 6, 9, 10]
p = 21 and q = 24
Now, notice that for every element in a, we can calculate the range of elements in B that, when added to the element, would have a sum between p and q. We can actually find this range in O(logW) time by using what is called Binary Search. Specifically, if we were looking to pair the first number in A with numbers in B, we would binary search for the index of the first element that is >= 12 and then binary search for the index of the last element that is <= 15. The number of elements in B that would work in a pairing with the element from A is then just equal to 1 plus the difference between the two indexes.
Overall, this algorithm would have a complexity of O(WlogW + VlogW) (or O(VlogV + WlogV); if you want to go above and beyond your program could decide to sort the larger array to save time on testing). This is because sorting an array with N elements takes O(NlogN) time, and because each binary search over a sorted array with N elements takes O(logN).
This can also be solved in following way,
First sort both arrays,
[9, 14, 5, 8, 12, 2, 16] => [2, 5, 8, 9, 12, 14, 16]
[6, 2, 9, 3, 10] => [2, 3, 6, 9, 10]
Now iterate all elements of smaller array and do following,
[2, 3, 6, 9, 10],
current element is 2, subtract it with p, lets say it is num it means,
num = p - 2 = 21 - 2 = 19
Then all numbers in other array, grater than of equals to 19 will make sum 21 with 2. But no element in other array is grater than or equals to 19 It means by adding 2 with any element of other array can not grater than or equals to p,
Next element which is 3 and it also can not fulfill the requirement, same can be done with other element, so let's directly move to element 9 for explanation,
[2, 3, 6, 9, 10]
num = p - 9 = 21 - 9 = 12 and by getting lower bound of 12, we will get all numbers, those sum with 9 will be grater than or equal to p(21), as highlighted below,
[2, 5, 8, 9, 12, 14, 16],
Sum of these numbers with 9 is grater than or equals to p, now it is time to find how may of them will produce sum which is less then or equals to q, so to doing that we have to do following,
num = q - 9 = 24 - 9 = 15 and by finding upper bound of 15 will give all the numbers sum with 9 shall be less than of equals to q as highlighted below,
[2, 5, 8, 9, 12, 14, 16],
This way you can find all combinations having sum, p >= sum <= q,
#include <iostream>
#include <vector>
#include <algorithm>
std::size_t combinationCount(int p, int q, std::vector<int> arr1, std::vector<int> arr2){
std::sort(arr1.begin(), arr1.end());
std::sort(arr2.begin(), arr2.end());
std::vector<int>::const_iterator it1 = arr1.cbegin();
std::vector<int>::const_iterator endIt1 = arr1.cend();
std::vector<int>::const_iterator it2 = arr2.cbegin();
std::vector<int>::const_iterator endIt2 = arr2.cend();
if(arr2.size() < arr1.size()){
std::swap(it1, it2);
std::swap(endIt1, endIt2);
}
std::size_t count = 0;
for(; endIt1 != it1; ++it1){
int num = p - *it1;
std::vector<int>::const_iterator lowBoundOfPIt = std::lower_bound(it2, endIt2, num);
if(endIt2 != lowBoundOfPIt){
num = q - *it1;
std::vector<int>::const_iterator upBoundOfQIt = std::upper_bound(it2, endIt2, num);
count += (upBoundOfQIt - lowBoundOfPIt);
}
}
return count;
}
int main(){
std::cout<< "count = "<< combinationCount(21, 24, {9, 14, 5, 8, 12, 2, 16}, {6, 2, 9, 3, 10})<< '\n';
}
Output : 5
I have a list of numbers stored in a standard vector. Some of the numbers are children of other numbers. Here is an example
3, 4
3, 5
5, 6
7, 3
8, 9
8, 1
8, 2
9, 8
Or as a graph:
1 2 3-4 5-6 7 8-9
|-------------|
|-----------|
|---|
|-------|
That is there are two clusters 3,4,5,6,7 and 1,2,8,9. The root number is the smallest number of a cluster. Here 3 and 1. I would like to know which algorithms I can use to extract a list like this:
3, 4
3, 5
3, 6
3, 7
1, 2
1, 8
1, 9
An algorithm similar disjoint set union algorithm can help you:
Initialize N disjoint subset, each subset has exactly one number, and root of number i(r(i)) is i.
For each edge (u, v), you can assign:
t = min(r(u), r(v))
r(u) = t
r(v) = t
For each i with i != r(i), you can write out [r(i) - i].
I want to check whether or not a certain element of a 2d vector is within an index range. For example, I have the following vector:
{1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12, 13, 14, 15}
How might I check whether or not the element number 7 (or [1][1]) is within the index range of 0 to 2 on the x axis and 0 to 1 on the y axis? Or in other words a 3x2 partition of the vector from the top left corner.
For the y axis you can do it like this:
index/width < yLimit
For the x axis, it would be like this:
index%width < xLimit
where width is the width of the 2d array, and xLimit and yLimit are the maximum you want your x-axis number and your y-axis number to be respectively.
Note that this number should be greater than or equal to 0 anyway, since negative indices are not a thing in C++.
Also note that I use < here, but I recon if you want to include 1 or 2 in your possible indices, you should use <= instead.
If you want them together, a logical and will do nicely:
index/width < yLimit && index%width < xLimit
I have an array of prime numbers from 2 to 997. How do you display array values with upper and lower limits? For example:
Upper and lower limits: 0 20
Output:
2, 3, 5, 7, 11, 13, 17, 19
Loop on the array till you find a number bigger than the lower limit, Then loop and display until you find a number bigger than the upper limit.
My question is whether or not a heap can be "correct". I have an assignment asking me to do a heap sort but first build a heap using an existing array. If I look through the grader code it shows me that there is an exact answer. The way T implemented the heap build I get a slightly different answer but as far as i know is by definition a heap and therefore correct.
The "correct" array order is
{15, 12, 6, 11, 10, 2, 3, 1, 8}
but I get
{15, 12, 10, 11, 2, 6, 3, 1, 8}
The original vector is
{2, 8, 6, 1, 10, 15, 3, 12, 11}
void HeapSort::buildHeap(std::vector<CountedInteger>& vector)
{
std::vector<CountedInteger> temp;
for(int i = 0; i < vector.size(); i++)
{
temp.push_back(vector[i]);
fixDown(temp, i);
}
vector.swap(temp);
for(int i = 0; i < vector.size(); i++)
{
std::cout<< vector[i]<<std::endl;
}
}
void HeapSort::sortHeap(std::vector<CountedInteger>& vector)
{
}
inline unsigned int HeapSort::p(int i)
{
return ((i-1)/2);
}
void HeapSort::fixDown(std::vector<CountedInteger>& vector, int node)
{
if(p(node) == node) return;
if(vector[node] > vector[p(node)])
{
CountedInteger temp = vector[node];
vector[node] = vector[p(node)];
vector[p(node)] = temp;
fixDown(vector, p(node));
}
There are many possible ways to create a max-heap from an input. You give the example:
15, 12, 10, 11, 2, 6, 3, 1 8
15
12 10
11 2 6 3
1 8
It fulfills the heap criterion, so it is a correct max-heap. The other example is:
15, 12, 6, 11, 10, 2, 3, 1, 8
15
12 6
11 10 2 3
1 8
This also fulfills the heap criterion, so it is also a correct max-heap.
Max-heap criterion: Each node is greater than any of its child nodes.
A simpler example is 1, 2, 3, for which there are two heaps,
3 3
/ \ / \
1 2 2 1
Creating a heap out of an array is definitely an operation that can result in multiple different but valid heaps.
If you look at a trivial example, it is obvious that at least some subtrees of one node could switch positions. In the given example, 2 and 7 could switch positions. 25 and 1 could also switch positions. If the heap has minimum and maximum depth equal, then the subtrees of any node can switch positions.
If your grader is automatic, it should be implemented in a way to check the heap property and not the exact array. If your grader is a teacher, you should formally prove the correctness of your heap in front of them, which is trivial.