I am given N numbers a[1..N] and 2 other integers L and H. How can I Count the number of tuples (i,j,k) satisfying i < j < k and L <= a[i] + a[j] + a[k] <= H.
1 <= T <= 100
1 <= N <= 1000
1 <= L <= H <= 1000000
1 <= a[i] <= 1000000
PS: Need Better Solution than N2logn
Solution
Since my C/C++ is somewhat rusty and this is primarily an algorithms question, I will write in pseudocode (mostly correct C/C++ with bits of algorithms that would take a while to write out).
If you have at least sizeof(int)*10^12 bytes of memory and time available, you can use this algorithm with time complexity O(n^2 * log(n)).
// Sort the N numbers using your favorite, efficient sorting method. (Quicksort, mergesort, etc.) [O(n*log(n))].
int[] b = sort(a)
int[] c = int[length(b)^2];
// Compute the sums of all of the numbers (O(n^2))
for(int i = 0; i < length(b); i++){
for (int j = i; j < length(b); j++){
c[i*length(b)+j] = b[i]+b[j];
}
}
// Sort the sum list (you can do the sorts in-place if you are comfortable) - O(n^2*log(n))
d = sort(c);
// For each number in your list, grab the list of of sums so that L<=num+sum<=H O(n)
// Use binary search to find the lower, upper bounds O(log(n))
// (Total complexity for this part: O(n*log(n))
int total = 0;
for (int i = 0; i < b; i++){
int min_index = binary_search(L-b[i]); // search for largest number <= L-b[i]
int max_index = binary_search(H-b[i]); // search for smallest number >= H-b[i]
total += max_index - min_index + 1; // NOTE: This does not handle edge cases like not finding any sums that work
}
return total;
A basic approach:
for (i=0; i<N; i++) {
for (j=i+1; j<N; j++) {
for (k=j+1; k<N; k++) {
int sum = a[i] + a[j] + a[k];
if (L <= sum && sum <= H) number_of_tuples++;
}
}
}
Possibly better (might have a mistake in it, but the basic idea is to break if you're already over the maximum):
for (i=0; i<N; i++) {
if (a[i] > H) continue;
for (j=i+1; j<N; j++) {
if (a[i] + a[j] > H) continue;
for (k=j+1; k<N; k++) {
int sum = a[i] + a[j] + a[k];
if (L <= sum && sum <= H) number_of_tuples++;
}
}
}
int find_three(int arr[], int c, int l,int h)
{
int i, j, e, s, k;
int count =0;
sort(arr,arr+c);
c--;
while(arr[c]>h)
c--;
int sum=0;
for (int i = 0; i<=c-2;i++)
{ sum=arr[i]+arr[i+1]+arr[i+2];
if(sum>h)
break;
for(j=i+1;j<=c-1;j++)
{
for(k=j+1;k<=c;k++)
{ sum=arr[i]+arr[j]+arr[k];
if(sum>=l &&sum<=h)
count++;
if(sum>h)
break;
}
if(sum>h)
break;
}
}
return count;
}
Related
I'm trying to implement a quick program to solve a system of linear equations. The program reads the input from a file and then writes the upper-triangular system and solutions to a file. It is working with no pivoting, but when I try to implement the pivoting it produces incorrect results.
As example input, here is the following system of equations:
w+2x-3y+4z=12
2w+2x-2y+3z=10
x+y=-1
w-x+y-2z=-4
I expect the results to be w=1, x=0, y=-1 and z=2. When I don't pivot, I get this answer (with some rounding error on x). When I add in the pivoting, I get the same numbers but in the wrong order: w=2,x=1,y=-1 and z=0.
What do I need to do to get these in the correct order? Am I missing a step somewhere? I need to do column swapping instead of rows because I need to adapt this to a parallel algorithm later that requires that. Here is the code that does the elimination and back substitution:
void gaussian_elimination(double** A, double* b, double* x, int n)
{
int maxIndex;
double temp;
int i;
for (int k = 0; k < n; k++)
{
i = k;
for (int j = k+1; j < n; j++)
{
if (abs(A[k][j]) > abs(A[k][i]))
{
i = j;
}
}
if (i != k)
{
for (int j = 0; j < n; j++)
{
temp = A[j][k];
A[j][k] = A[j][i];
A[j][i] = temp;
}
}
for (int j = k + 1; j < n; j++)
{
A[k][j] = A[k][j] / A[k][k];
}
b[k] = b[k] / A[k][k];
A[k][k] = 1;
for (i = k + 1; i < n; i++)
{
for (int j = k + 1; j < n; j++)
{
A[i][j] = A[i][j] - A[i][k] * A[k][j];
}
b[i] = b[i] - A[i][k] * b[k];
A[i][k] = 0;
}
}
}
void back_substitution(double**U, double*x, double*y, int n)
{
for (int k = n - 1; k >= 0; k--)
{
x[k] = y[k];
for (int i = k - 1; i >= 0; i--)
{
y[i] = y[i] - x[k]*U[i][k];
}
}
}
I believe what you implemented is actually complete pivoting.
With complete pivoting, you must keep track of the permutation of columns, and apply the same permutation to your answer.
You can do this with an array {0, 1, ..., n}, where you swap the i'th and k'th values in the second loop. Then, rearange the solution using this array.
If what you were trying to do is partial pivoting, you need to look for the maximum in the respective row, and swap the rows and the values of 'b' accordingly.
Let's say I have three vectors.
#include <vector>
vector<long> Alpha;
vector<long> Beta;
vector<long> Gamma;
And let's assume I've filled them up with numbers, and that we know they're all the same length. (and we know that length ahead of time - let's say it's 3.)
What I want to have at the end is the minimum of all sums Alpha[i] + Beta[j] + Gamma[k] such that i, j, and k are all unequal to each other.
The naive approach would look something like this:
#include <climits>
long min = LONG_MAX;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int k=0; k < 3; k++) {
if (i != j && i != k && j != k) {
long sum = Alpha[i] + Beta[j] + Gamma[k];
if (sum < min)
min = sum;
}
}
}
}
Frankly, that code doesn't feel right. Is there a faster and/or more elegant way - one that skips the redundant iterations?
The computational complexity of your algorithm is an O(N^3). You can save a very small bit by using:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if ( i == j )
continue;
long sum1 = Alpha[i] + Beta[j];
for (int k=0; k < 3; k++) {
if (i != k && j != k) {
long sum2 = sum1 + Gamma[k];
if (sum2 < min)
min = sum2;
}
}
}
}
However, the complexity of the algorithm is still O(N^3).
Without the if ( i == j ) check, the innermost loop will be executed N^2 times. With that check, you will be able to avoid the innermost loop N times. It will be executed N(N-1) times. The check is almost not worth it .
If you can temporarily modify the input vectors, you can swap the used values with the end of the vectors, and just iterate over the start of the vectors:
for (int i = 0; i < size; i++) {
std::swap(Beta[i],Beta[size-1]); // swap the used index with the last index
std::swap(Gamma[i],Gamma[size-1]);
for (int j = 0; j < size-1; j++) { // don't try the last index
std::swap(Gamma[j],Gamma[size-2]); // swap j with the 2nd-to-last index
for (int k=0; k < size-2; k++) { // don't try the 2 last indices
long sum = Alpha[i] + Beta[j] + Gamma[k];
if (sum < min) {
min = sum;
}
}
std::swap(Gamma[j],Gamma[size-2]); // restore values
}
std::swap(Beta[i],Beta[size-1]); // restore values
std::swap(Gamma[i],Gamma[size-1]);
}
I have the following attempt to write a selection sort in C++:
#include <iostream>
using namespace std;
int main()
{
int a[10], k, i, j, n, aux;
cin >> n;
for (i = 0; i <= n-1; i++)
cin >> a[i];
k = a[0];
for (i = 0; i <= n - 2; i++) {
for (j = i + 1; j <= n-1; j++)
if (k > a[j])
k = a[j];
for (j = i + 1; j <= n-1; j++)
if (k == a[j]) {
aux = a[i];
a[i] = a[j];
a[j] = aux;
}
k = a[i + 1];
}
for (i = 0; i <= n-1; i++)
cout << a[i];
return 0;
}
From my tests it returns sorted arrays, so I think it's correct.
But I also have to explain why the main for loop of the sort only takes n-1 steps instead of n. Could anyone explain the "why" part to me?
Consider how many steps are required if n is 1.
Basically, you don't need to sort the first element.
The sorting is done by comparing pairs of elements.
How many pairs are there in an array of N elements? (hint: N-1)
This animation might help explain how the algorithm works.
How do I solve following programming riddle in O(N)?
Array of integers: Tab[N]
Find max(Tab[K] - K + Tab[L] + L)
where 0 <= K <= L <= N
The only solution I can come up with is O(N^2) where I compare each element and update maximum sum.
int curr_max = INTEGER_MIN;
for(int i = 0; i < N; i++){
for(int j = i; j < N; j++){
curr_max = max(Tab[i]-i + Tab[j] + j,curr_max);
}
}
In general, a possible way to solve such kind of tasks, due to K<=L constraint, is to use pre-calculated running max. (The version below can be optimized, but anyway has O(N) time and space complexity.)
int t[N+1]; // input
int a[N+1]; // running max t[i]-i, left to right
a[0] = t[0]-0;
for (int i = 1; i <= N; ++i)
a[i] = max(a[i-1], t[i]-i);
int b[N+1]; // running max t[i]+i, right to left
b[N] = t[N]+N;
for (int i = N-1; i >= 0; --i)
b[i] = max(b[i+1], t[i]+i);
int mx = a[0] + b[0];
for (int i = 1; i <= N; ++i)
mx = max(mx, a[i] + b[i]);
However, in our case, it can be shown that if K: Tab[K]-K -> max and L: Tab[K]+K -> max then K<=L. In other words, if L and K are indices of the two maxima respectively, the property L<=K holds. Therefore, the naïve approach should work too:
int K = 0, L = 0;
for (int i = 1; i <= N; ++i) {
if (t[i]-i > t[K]-K)
K = i;
if (t[i]+i > t[L]+L)
L = i;
}
assert(K <= L);
int mx = t[K]-K + t[L]+L;
How about:
int L_max = INTEGER_MIN;
int K_max = INTEGER_MIN;
for(int i=0; i<N; i++)
{
K_max = max(Tab[i] -i, K_max);
L_max = max(Tab[i] +i, L_max);
}
curr_max = K_max + L_max;
Note that it does not validate K <= L, neither does the code in the question.
I faced this problem in an interview challenge
K caterpillars are eating their way through N leaves, each caterpillar
falls from leaf to leaf in a unique sequence, all caterpillars start
at a twig at position 0 and falls onto the leaves at position between
1 and N. Each caterpillar j has an associated jump number Aj. A
caterpillar with jump number j eats leaves at positions that are
multiple of j. It will proceed in the order j, 2j, 3j…. till it
reaches the end of the leaves and it stops and build its cocoon. Given
a set A of K elements , we need to determine the number
of uneaten leaves.
Constraints:
1 <= N <= 109
1 <= K <= 15
1 <= A[i] <= 109
Input format:
N = No of uneaten leaves.
K = No. of caterpillars.
A = Array of integer.
jump numbers Output:
The integer nu. Of uneaten leaves
Sample Input:
10
3
2
4
5
Output:
4
Explanation:
[2, 4, 5] is the 3-member set of jump numbers. All leaves which are multiple of 2, 4, and 5 are eaten. Only 4 leaves which are numbered 1,3,7,9 are left.
the naive approach for solving this question is have a Boolean array of all N numbers, and iterate over every caterpillar and remember the eaten leaves by it.
int uneatenusingNaive(int N, vector<int> A)
{
int eaten = 0;
vector<bool>seen(N+1, false);
for (int i = 0; i < A.size(); i++)
{
long Ai = A[i];
long j = A[i];
while (j <= N && j>0)
{
if (!seen[j])
{
seen[j] = true;
eaten++;
}
j += Ai;
}
}
return N - eaten;
}
this approach passed 8 out of 10 test cases and give wrong answer for 2 cases.
another approach using Inclusion Exclusion principle, explanation for it can be found here and here
below is my code for the second approach
int gcd(int a, int b)
{
if (b == 0)
return a;
return gcd(b, a%b);
}
int lcm(int i, int j)
{
return i*j / gcd(i, j);
}
vector<vector<int>> mixStr(vector<vector<int>> & mix, vector<int>& A, unordered_map<int, int> & maxStart)
{
vector<vector<int>> res;
if (mix.size() == 0)
{
for (int i = 0; i < A.size(); i++)
{
vector<int> tmp;
tmp.push_back(A[i]);
res.push_back(tmp);
}
return res;
}
for (int i = 0; i<mix.size(); i++)
{
int currSlotSize = mix[i].size();
int currSlotMax = mix[i][currSlotSize - 1];
for (int j = maxStart[currSlotMax]; j < A.size(); j++)
{
vector<int> tmp(mix[i]);
tmp.push_back(A[j]);
res.push_back(tmp);
}
}
return res;
}
int uneatenLeavs(int N, int k, vector<int> A)
{
int i = 0;
vector<vector<int>> mix;
bool sign = true;
int res = N;
sort(A.begin(), A.end());
unordered_map<int,int> maxStart;
for (int i = 0; i < A.size(); i++)
{
maxStart[A[i]] = i + 1;
}
int eaten = 0;
while (mix.size() != 1)
{
mix = mixStr(mix, A, maxStart);
for (int j = 0; j < mix.size(); j++)
{
int _lcm = mix[j][0];
for (int s = 1; s < mix[j].size(); s++)
{
_lcm = lcm(mix[j][s], _lcm);
}
if (sign)
{
res -= N / _lcm;
}
else
{
res += N / _lcm;
}
}
sign = !sign;
i++;
}
return res;
}
this approach passed only one 1/10 test case. and for the rest of test cases time limit exceeded and wrong answer.
Question:
What am I missing in first or second approach to be 100% correct.
Using Inclusion-Exclusion theorem is correct approach, however, your implementation seems to be too slow. We can use bitmasking technique to obtain a O(K*2^K) time complexity.
Take a look at this:
long result = 0;
for(int i = 1; i < 1 << K; i++){
long lcm = 1;
for(int j = 0; j < K; j++)
if(((1<<j) & i) != 0) //if bit j is set, compute new LCM after including A[j]
lcm *= A[j]/gcd(lcm, A[j]);
if(number of bit set in i is odd)
result += N/lcm;
else
result -= N/lcm;
}
For your first approach, an O(N*K) time complexity algorithm, with N = 10^9 and K = 15, it will be too slow, and can cause memory limit exceed/time limit exceed.
Notice that lcm can be larger than N, so, additional check is needed.