I have built recursive function to compute Pascal's triangle values.
Is there a way to optimize it?
Short reminder about Pascal's triangle: C(n, k) = C(n-1, k-1) + C(n-1, k)
My code is:
int Pascal(int n, int k) {
if (k == 0) return 1;
if (n == 0) return 0;
return Pascal(n - 1, k - 1) + Pascal(n - 1, k);
}
The inefficiency I see is that it stores some values twice.
Example:
C(6,2) = C(5,1) + C(5,2)
C(6,2) = C(4,0) + C(4,1) + C(4,1) + C(4,2)
it will call C(4,1) twice
Any idea how to optimize this function?
Thanks
The following routine will compute the n-choose-k, using the recursive definition and memoization. The routine is extremely fast and accurate:
inline unsigned long long n_choose_k(const unsigned long long& n,
const unsigned long long& k)
{
if (n < k) return 0;
if (0 == n) return 0;
if (0 == k) return 1;
if (n == k) return 1;
if (1 == k) return n;
typedef unsigned long long value_type;
class n_choose_k_impl
{
public:
n_choose_k_impl(value_type* table,const value_type& dimension)
: table_(table),
dimension_(dimension / 2)
{}
inline value_type& lookup(const value_type& n, const value_type& k)
{
const std::size_t difference = static_cast<std::size_t>(n - k);
return table_[static_cast<std::size_t>((dimension_ * n) + ((k < difference) ? k : difference))];
}
inline value_type compute(const value_type& n, const value_type& k)
{
// n-Choose-k = (n-1)-Choose-(k-1) + (n-1)-Choose-k
if ((0 == k) || (k == n))
return 1;
value_type v1 = lookup(n - 1,k - 1);
if (0 == v1)
v1 = lookup(n - 1,k - 1) = compute(n - 1,k - 1);
value_type v2 = lookup(n - 1,k);
if (0 == v2)
v2 = lookup(n - 1,k) = compute(n - 1,k);
return v1 + v2;
}
value_type* table_;
const value_type dimension_;
};
static const std::size_t static_table_dim = 100;
static const std::size_t static_table_size = static_cast<std::size_t>((static_table_dim * static_table_dim) / 2);
static value_type static_table[static_table_size];
static bool static_table_initialized = false;
if (!static_table_initialized && (n <= static_table_dim))
{
std::fill_n(static_table,static_table_size,0);
static_table_initialized = true;
}
const std::size_t table_size = static_cast<std::size_t>(n * (n / 2) + (n & 1));
unsigned long long dimension = static_table_dim;
value_type* table = 0;
if (table_size <= static_table_size)
table = static_table;
else
{
dimension = n;
table = new value_type[table_size];
std::fill_n(table,table_size,0LL);
}
value_type result = n_choose_k_impl(table,dimension).compute(n,k);
if (table != static_table)
delete [] table;
return result;
}
Keep a table of previously returned results (indexed by their n and k values); the technique used there is memoization. You can also change the recursion to an iteration and use dynamic programming to fill in an array containing the triangle for n and k values smaller than the one you are trying to evaluate, then just get one element from it.
Related
I am trying to solve some range minimum query where the minima must be above some constant.
Problem:
Given some positive integers a1, ... aN. For each query of integers l, r, d find the minimal element that is still greater than d, that is find min{a_i | l <= i <= r, a_i > d}.
I already tried the segment tree algorithm with an additional sparse table to speed up the queries when all elements are above d. This gave me an complexity of O(N * log(N) + Q * log(N)). Using the sparse table did not improve the complexity, but it pruned a lot of the calls for the segment tree query.
However, this algorithm is still too slow. Does anybody has a faster algorithm that I could try?
Edit:
People are pointing out that it has to do with my implementation and that I am using the correct data structure. So here is my code, maybe I did something wrong that increased the complexity:
#include <bits/stdc++.h>
const int32_t MAX_N = 100005;
const int32_t LOG_N = 10;
int32_t sparse_table[MAX_N][LOG_N];
std::vector<int32_t> deviations;
std::vector<int32_t> segment_tree;
void build_sparse_table(int32_t N)
{
for (int32_t i = 0; i < N; i++) {
sparse_table[i][0] = deviations[i];
}
for (int32_t k = 1; k < LOG_N; k++) {
for (int32_t i = 0; i + (1 << k) - 1 < N; i++) {
sparse_table[i][k] = std::min(sparse_table[i][k - 1], sparse_table[i + (1 << (k - 1))][k - 1]);
}
}
}
void build_segment_tree(int32_t p, int32_t l, int32_t r)
{
if (l == r) {
segment_tree[p] = deviations[l];
return;
}
int32_t m = (l + r) / 2;
build_segment_tree(2 * p, l, m);
build_segment_tree(2 * p + 1, m + 1, r);
segment_tree[p] = std::min(segment_tree[2 * p], segment_tree[2 * p + 1]);
}
int32_t query_sparse_table(int32_t l, int32_t r)
{
int32_t length = r - l + 1;
int32_t k = 31 - __builtin_clz(length);
if (l > r || k >= LOG_N) {
return -1;
}
return std::min(sparse_table[l][k], sparse_table[r - (1 << k) + 1][k]);
}
int32_t query_segment_tree(int32_t p, int32_t l, int32_t r, int32_t i, int32_t j, int32_t d)
{
int32_t maybe_result = query_sparse_table(i, j);
if (maybe_result > d) {
return maybe_result;
}
if (i > j) {
return -1;
}
if (i == l && j == r) {
if (segment_tree[p] > d) {
return segment_tree[p];
}
}
if (l == r) {
return (segment_tree[p] > d) ? segment_tree[p] : -1;
}
int32_t m = (l + r) / 2;
int32_t ql = query_segment_tree(2 * p, l, m, i, std::min(j, m), d);
int32_t qr = query_segment_tree(2 * p + 1, m + 1, r, std::max(i, m + 1), j, d);
return (ql != -1 && qr != -1) ? std::min(ql, qr) : std::max(ql, qr);
}
int32_t query_segment_tree(int32_t l, int32_t r, int32_t d)
{
return query_segment_tree(1, 0, deviations.size() - 1, l, r, d);
}
Here’s another approach, that runs in linearithmic time.
We sweep a quantity x from −∞ to ∞. Whenever x = d for some query, we
insert [ℓ, r] into an interval tree. Whenever x = ai for
some i, we delete all of the intervals that contain i, reporting i as
their result. We resolve nondeterminism by doing the latter before the
former.
The cost is sorting the array, sorting the intervals by d, merging them
into an event array, and performing an amortized logarithmic time
operation for each one.
I need to convert this recursive function into tail recursive function but i am getting the wrong output can any help me out with this.
Here is the function definition:
f(n) = 3f(n − 1) - f(n − 2) + n,
with initial conditions f(0) = 1 and f(1) = 2.
#include <iostream>
using namespace std;
int headRecursion(int n) {
if(n == 0) {
return 1;
}
if (n == 1) {
return 2;
}
return 3 * headRecursion(n - 1) - headRecursion(n - 2) + n;
}
int main(){
cout << endl << headRecursion(3);
return 0;
}
This is kind of an interesting problem. We can start with how to implement as a loop:
int minus2 = 1;
int minus1 = 2;
if (n == 0) return minus2;
if (n == 1) return minus1;
for( int i = 2; i <= n; i++)
{
int next = minus1 * 3 - minus2 + i;
minus2 = minus1;
minus1 = next;
}
return minus1;
The takeaway is we need to count UP. In order to make this tail recursive we need to pass in our accumulators (there is no reason to do this other than to show off, but it adds nothing to readability or efficiency)
int tailRecursive(int minus2, int minus1, int step, int n)
{
if (step == n) return minus1;
return tailRecursive(minus1, minus1*3 - minus2 + step+1, step+1, n);
}
you can use an intermediate to set it up and handle the n==0 case.
int calcIt(int n) {
if (n == 0) return 1;
// step must start with 1, since we handled 0 above
return tailRecursive(1, 2, 1, n);
}
Something along these lines:
std::pair<int, int> next_result(std::pair<int, int> prev_result, int n) {
return {3*prev_result.first - prev_result.second + n, prev_result.first};
}
std::pair<int, int> tailRecursion(int n) {
if (n == 0) {
return {1, 0};
}
if (n == 1) {
return {2, 1};
}
return next_result(tailRecursion(n-1), n);
}
int compute(int n) {
return tailRecursion(n).first;
}
int main(){
std::cout << compute(3) << std::endl;
}
Demo
The key is that you need a function that computes a pair {f(n), f(n-1)} given the previously computed pair {f(n-1), f(n-2)}
The link to the particular question is as follows: https://leetcode.com/problems/nth-magical-number/. My code is showing "Time Limit Exceeded" and I cannot figure out where actually lies the error in my code. My code is as follows:
class Solution {
public:
typedef unsigned int ull;
int gcd(int A,int B)
{
if(B==0)
return A;
else
return gcd(B,A%B);
}
int nthMagicalNumber(int N, int A, int B) {
ull m;
if(A<B)
{
int t;
t=A;
A=B;
B=t;
}
ull lcm=(A*B)/gcd(A,B);
ull l=2;
ull h=1e9;
ull n;
while(l<=h)
{
m=l+(h-1)/2;
n=(m/A)+(m/B)-(m/lcm);
if(n==N)
break;
else if(n<N)
l=m+1;
else if(n>N)
h=m-1;
}
ull x=(1e9)+7;
return (int)(m%x);
}
};
Can someone let me know where I am wrong and how can I correct the error?
You might want to use a debugger for that. This solution is just very similar (using Binary Search with gcd) and would pass through:
// This block might trivially optimize the exec time;
// Can be removed;
const static auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
return 0;
}();
#include <cstdint>
#include <vector>
const static struct Solution {
using SizeType = std::uint_fast64_t;
static constexpr SizeType kMod = 1e9 + 7;
const SizeType nthMagicalNumber(
const SizeType N,
const SizeType A,
const SizeType B
) {
const SizeType lowest_common_multiple = A * B / getGreatestCommonDivisor(A, B);
SizeType lo = 2;
SizeType hi = 1e14;
while (lo < hi) {
SizeType mid = lo + (hi - lo) / 2;
if (mid / A + mid / B - mid / lowest_common_multiple < N) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo % kMod;
}
// __gcd(a, b)
static const SizeType getGreatestCommonDivisor(
const SizeType a,
const SizeType b
) {
if (not b) {
return a;
}
return getGreatestCommonDivisor(b, a % b);
}
};
Instead of ull, here we are using std::uint_fast64_t.
References
For additional details, please see the Discussion Board which you can find plenty of well-explained accepted solutions in there, with a variety of languages including efficient algorithms and asymptotic time/space complexity analysis1, 2.
You can try this approach in C++ for that question my solution got accepted:
class Solution {
public:
long long gcd(long long a, long long b) {
if(b == 0)
return a;
return gcd(b, a % b);
}
int nthMagicalNumber(long long n, long long a, long long b) {
long long end = max(a, b) * (n + 1);
long long min = 1;
long long lcm = (a / gcd(a, b)) * b;
long long curr, mid;
while(min <= end) {
mid = (end - min)/2 + min;
curr = (mid / a) + (mid / b) - (mid / lcm);
if(curr > n) {
end = mid - 1;
} else if(curr < n) {
min = mid + 1;
} else {
break;
}
}
while((mid % a != 0) && (mid % b != 0)) {
mid--;
}
return mid % (1000000007);
}
};
I'm trying to solve a coding challenge on hacker rank which requires one to calculate binomial coefficients mod a prime, i.e.
nchoosek(n, k, p)
I'm using the code from this answer that works for the first three sets of inputs but begins failing on the 4th. I stepped through it in the debugger and determined that the issue arises when:
n % p == 0 || k % p == 0
I just need to know how to modify my current solution to handle the specific cases where n % p == 0 or k % p == 0. None of the answers I've found on stack exchange seem to address this specific case. Here's my code:
#include <iostream>
#include <fstream>
long long FactorialExponent(long long n, long long p)
{
long long ex = 0;
do
{
n /= p;
ex += n;
}while(n > 0);
return ex;
}
unsigned long long ModularMultiply(unsigned long long a, unsigned long long b, unsigned long p) {
unsigned long long a1 = (a >> 21), a2 = a & ((1ull << 21) - 1);
unsigned long long temp = (a1 * b) % p; // doesn't overflow under the assumptions
temp = (temp << 21) % p; // this neither
temp += (a2 * b) % p; // nor this
return temp % p;
}
unsigned long long ModularInverse(unsigned long long k, unsigned long m) {
if (m == 0) return (k == 1 || k == -1) ? k : 0;
if (m < 0) m = -m;
k %= m;
if (k < 0) k += m;
int neg = 1;
unsigned long long p1 = 1, p2 = 0, k1 = k, m1 = m, q, r, temp;
while(k1 > 0) {
q = m1 / k1;
r = m1 % k1;
temp = q*p1 + p2;
p2 = p1;
p1 = temp;
m1 = k1;
k1 = r;
neg = !neg;
}
return neg ? m - p2 : p2;
}
// Preconditions: 0 <= k <= min(n,p-1); p > 1 prime
unsigned long long ChooseModTwo(unsigned long long n, unsigned long long k, unsigned long p)
{
// reduce n modulo p
n %= p;
// Trivial checks
if (n < k) {
return 0;
}
if (k == 0 || k == n) {
return 1;
}
// Now 0 < k < n, save a bit of work if k > n/2
if (k > n/2) {
k = n-k;
}
// calculate numerator and denominator modulo p
unsigned long long num = n, den = 1;
for(n = n-1; k > 1; --n, --k)
{
num = ModularMultiply(num, n, p);
den = ModularMultiply(den, k, p);
}
den = ModularInverse(den,p);
return ModularMultiply(num, den, p);
}
// Preconditions: 0 <= k <= n; p > 1 prime
long long ChooseModOne(long long n, long long k, const unsigned long p)
{
// For small k, no recursion is necessary
if (k < p) return ChooseModTwo(n,k,p);
unsigned long long q_n, r_n, q_k, r_k, choose;
q_n = n / p;
r_n = n % p;
q_k = k / p;
r_k = k % p;
choose = ChooseModTwo(r_n, r_k, p);
// If the exponent of p in choose(n,k) isn't determined to be 0
// before the calculation gets serious, short-cut here:
// if (choose == 0) return 0;
return ModularMultiply(choose, ChooseModOne(q_n, q_k, p), p);
}
unsigned long long ModularBinomialCoefficient(unsigned long long n, unsigned long long k, const unsigned long p)
{
// We deal with the trivial cases first
if (k < 0 || n < k) return 0;
if (k == 0 || k == n) return 1;
// Now check whether choose(n,k) is divisible by p
if (FactorialExponent(n, p) > FactorialExponent(k, p) + FactorialExponent(n - k, p)) return 0;
// If it's not divisible, do the generic work
return ChooseModOne(n, k, p);
}
int main() {
//std::ifstream fin ("input03.txt");
std::ifstream fin ("test.in");
int kMod = 1000003;
int T;
fin >> T;
int N = T;
//std::cin >> T;
unsigned long long n, k;
unsigned long long a, b;
int result[N];
int index = 0;
while (T--) {
fin >> n >> k;
a = ModularBinomialCoefficient(n - 3, k, kMod);
b = ModularBinomialCoefficient(n + k, n - 1, kMod);
// (1 / (n + k) * nCk(n - 3, k) * nCk(n + k, n - 1)) % 1000003
unsigned long long x = ModularMultiply(a, b, kMod);
unsigned long long y = ModularMultiply(x, ModularInverse((n + k), kMod), kMod);
result[index] = y;
index++;
}
for(int i = 0; i < N; i++) {
std::cout << result[i] << "\n";
}
return 0;
}
Input:
6
90 13
65434244 16341234
23424244 12341234
424175 341198
7452123 23472
56000168 16000048
Output:
815483
715724
92308
903465
241972
0 <-- Incorrect, should be: 803478
Constraints:
4 <= N <= 10^9
1 <= K <= N
You can use Lucas' theorem to reduce the problem to ceil(log_P(N)) subproblems with k, n < p: Write n = n_m * p^m + ... + n_0 and k = k_m * p^m + ... + k_0 in base p (n_i, k_i < p are the digits), then we have
C(n,k) = PROD(i = 0 to m, C(n_i, k_i)) (mod p)
The subproblems are easy to solve, because every factor of k! has an inverse modulo p. You get an algorithm with runtime complexity O(p log(n)), which is better than that of Ivaylo's code in case of p << n, if I understand it correctly.
int powmod(int x, int e, int p) {
if (e == 0) return 1;
if (e & 1) return (long long)x * powmod(x, e - 1, p) % p;
long long rt = powmod(x, e / 2, p);
return rt * rt % p;
}
int binom_coeff_mod_prime(int n, int k, int p) {
long long res = 1;
while (n || k) {
int N = n % p, K = k % p;
for (int i = N - K + 1; i <= N; ++i)
res = res * i % p;
for (int i = 1; i <= K; ++i)
res = res * powmod(i, p - 2, p) % p;
n /= p;
k /= p;
}
return res;
}
I suggest you use factorization to compute the number of combinations without division. I've got code for doing so here, originally inspired by Fast computation of multi-category number of combinations (I still would like to post a proper answer to that, if some kind souls would reopen it).
My code stores the result as a table of factors, doing the modular multiplication to expand the result should be quite straightforward.
Probably not practical for n in the range of 10**9, though, since the sieve will be quite massive and take a while to construct.
I have a problem with the Quick Sort algorithm that I'm trying to implement.
I take a course of Fundamental Algorithms and we're provided for the laboratory assignments with pseudocode for various argorithms to implement. These algorithms are taken from Cormen and assimilated to C++ language and we're supposed to verify efficiency and generate charts for the number of assignments and comparisons within.
Now the question:
The following code is supposed to make a Quick Sort on an array of 10000 numbers and work with it in the Best Case scenario (taking the pivot of the array always at the middle):
int partition(int *a, int p, int r) {
int x = a[r];
countOpQS++;
int index = p - 1;
for (int count = p; count <= (r - 1); count++) {
if (a[count] <= x) {
index += 1;
swap(a[index], a[count]);
countOpQS += 3;
}
countOpQS++;
}
swap(a[index + 1], a[r]);
countOpQS += 3;
return (index + 1);
}
int select(int *a, int p, int r, int index) {
if (p == r) {
return a[p];
}
int q;
q = partition(a, p, r);
//countOpQS++;
int k = q - p + 1;
if (index <= k) {
return select(a, p, q - 1, index);
} else {
return select(a, q + 1, r, index - k);
}
}
void bestQuickSort(int *a, int p, int r) {
if (p < r) {
select(a, p, r, (r - p + 1) / 2);
bestQuickSort(a, p, (r - p + 1) / 2);
bestQuickSort(a, ((r - p + 1) / 2) + 1, r);
}
}
The call in the main function is done by:
for (index = 100; index <= 10000; index += 100) {
countOpQS = 0;
for (int k = 0; k < index; k++) {
a[k] = rand();
}
bestQuickSort(a, 1, index);
out3 << index << ", " << countOpQS << "\n";
}
It should be doable with these methods, but it jumps into stack overflow pretty quickly while running. I even raised the reserved stack in Visual Studio, due to it being a necessity while going into the worst case possible (already ordered array, random pivot).
Do you guys have any idea of why it doesn't work?
Firstly, you should know that your function select() rearranges the elements in the range [p, r], in such a way that the element at the index-th(note that index is one-based!) position is the element that would be in that position in a sorted sequence, just as std::nth_element does.
So when you chose the median element of the subarray by select(a, p, r, (r - p + 1) / 2);, the index of median is based on p.
For example: when p = 3, r = 5, so (r - p + 1) / 2 is 1, the median would be placed in a[4], it means you should call the function like this: select(a, 3, 5, 2). And after that, you just call the bestQuickSort() like this:
bestQuickSort(a, p, (r - p + 1) / 2); // (r - p + 1) / 2 is 1 now!
bestQuickSort(a, ((r - p + 1) / 2) + 1, r);
of course it doesn't work! The whole code for this is:
int select(int *a, int p, int r, int index) {
if (p == r) {
return a[p];
}
int q;
q = partition(a, p, r);
//countOpQS++;
int k = q - p + 1;
if(k== index)
return a[q];
else if (index <= k) {
return select(a, p, q - 1, index);
} else {
return select(a, q + 1, r, index - k);
}
}
void bestQuickSort(int *a, int p, int r) {
if (p < r) {
select(a, p, r, (r - p + 1) / 2 + 1); // the index passed to select is one-based!
int midpoint = p + (r - p + 1) / 2;
bestQuickSort(a, p, midpoint - 1);
bestQuickSort(a, midpoint + 1, r);
}
}
BTW, your version of quicksort didn't always run in best case, though every time you choose the exact median of the (sub)array, but the time complexity of select is not always O(n) since you simply choose the a[r] as the pivot, the worst-case performance of select is quadratic: O(n*n).