I'm trying to compute
,
where Ci is the i-th Catalan number.
To solve the problem, I loop from 0 to n and sum the product of two Catalan numbers:
BigInteger catalanSum = 0;
for (int i = 0; i <= n; i++)
catalanSum += catalan(i) * catalan(n - i);
The catalan function is returning the binomial coefficent divided by n + 1:
BigInteger catalan(int n)
{
return NchooseK(2 * n, n) / (n + 1);
}
And to compute the binomial coefficient I use this function:
BigInteger NchooseK(int n, int k)
{
BigInteger res = 1;
if (k > n - k)
k = n - k;
for (int i = 0; i < k; ++i)
{
res *= (n - i);
res /= (i + 1);
}
return res;
}
It works fine up to n = 1000, but as soon it get highers it really slows down alot. Is there any way I can optimize this calculation?
EDIT:
I sped up the computation by saving the catalans first using the following code-snippet, thanks to xanatos answer:
BigInteger[] catalans = new BigInteger[n+1];
BigInteger catalanSum = 0;
for (int i = 0; i <= n; i++)
catalans[i] = catalan(i);
for (int i = 0; i <= n; i++)
catalanSum += catalans[i] * catalans[n - i];
EDIT 2:
When catalan[i] == catalan[n - i], wouldn't the remaining half of computations have the same product as the first half?
The computation you are describing seems like the first recurrence relation for computing the nth Catalan Number (and you're needlessly applying a binomial computation as well when you could just use the Catalan numbers themselves in the recurrence). That's O(n^2) complexity plus the complexity for all the binomial computations. Why not use the second recurrence relation?
catalan(0) = 1
catalan(n + 1) = 2*(2*n + 1) / (n + 2) * n
There are two things you can do:
First, check OEIS for your sequence. You will find that the sequence has an entry. And this entry has a useful formula:
2*(2*n-1)*a(n-1) = (n+1)*a(n)
So, calculating the Catalan numbers can be done much more efficiently:
BigInteger lastCatalan = 1;
catalans[0] = lastCatalan;
for(int i = 1; i <= n; ++i)
{
lastCatalan = (2 * (2 * i - 1) * lastCatalan) / (i + 1);
catalans[i] = lastCatalan;
}
The second thing is that your summation is symmetric. I.e., you just need to sum half of the entries:
BigInteger catalanSum = 0;
for (int i = 0; i < (n + 1) / 2; i++)
catalanSum += catalans[i] * catalans[n - i];
catalanSum = 2 * catalanSum;
if (n % 2 == 0)
catalanSum += catalans[n / 2] * catalans[n / 2];
After גלעד ברקן pointed out that the sum you are looking for is the n+1-th Catalan number, this can be simplified drastically:
BigInteger catalanSum= 1;
for(int i = 1; i <= n + 1; ++i)
catalanSum = (2 * (2 * i - 1) * catalanSum) / (i + 1);
You could also cache the factorials.
Related
Is there an algorithm for calculating a factorial without using System.Numerics library? We receive an int number and we need to return factorial of this number as string(if n = 30, we should return "265252859812191058636308480000000", if n = 70, we should return "11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000" ect. Numbers are very big)
I tried to find out, did anyone already write an article about that, but I didn't find anything.
It suffices to implement multiplication of a large number as a string by a small integer.
Illustration: 12! = 11! x 12 is obtained by multiplying every digit by 12 and summing (with shifts):
39916800
36
108
108
12
72
96
0
0
---------
479001600
A lazy solution. It is possible to evaluate the factorial with just BigNum addition, replacing the multiplications by successive additions. (For n!, we will perform 1+2+3+...n-1 additions. This is acceptable for moderate n.)
The computation uses two pre-allocated string (arrays of char), which are initially filled with null bytes (Writeline skips them). When adding from right to left, we stop when we meet a null.
int n = 20;
// Factorial and temporary string; 100! fits in 158 digits
const int N = 158;
char[] f = new char[N], t = new char[N];
f[N - 1] = '1'; // 1!
// Product up to n by successive additions
for (int i = 2; i <= n; i++)
{
// t= f
f.CopyTo(t, 0);
for (int j = 0; j < i - 1; j++)
{
// f+= t, repeated i-1 times
int c = 0; // Carry
for (int k = N - 1; k >= 0; k--)
{
if (t[k] == 0 && c == 0) break; // Significant part exhausted
int d = Math.Max(0, t[k] - '0') + Math.Max(0, f[k] - '0') + c;
c= d / 10; d = d % 10; f[k] = (char)(d + '0'); // Next carry/digit
}
}
Console.WriteLine(f);
}
Output:
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000
2432902008176640000
static string FindFactorial(int n)
{
int[] result = new int[500000];
result[0] = 1;
int resultSize = 1;
for (int x = 2; x <= n; x++)
resultSize = Multiply(x, result, resultSize);
string factorial = "";
for (int i = resultSize - 1; i >= 0; i--)
factorial += result[i].ToString();
return factorial;
}
static int Multiply(int x, int[] result, int resultSize)
{
int carry = 0;
for (int i = 0; i < resultSize; i++)
{
int product = result[i] * x + carry;
result[i] = product % 10;
carry = product / 10;
}
while (carry != 0)
{
result[resultSize] = carry % 10;
carry /= 10;
resultSize++;
}
return resultSize;
}
This will work
Find then sum all the divisors from 1 to N.
The main problem is, that this code runs really poor with high numbers.
The following code was taken from: https://www.geeksforgeeks.org/sum-divisors-1-n
static int divisorSum(int n)
{
int sum = 0;
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j * j <= i; ++j)
{
if (i % j == 0)
{
if (i / j == j)
sum += j;
else
sum += j + i / j;
}
}
}
return sum;
}
Based on #Joel solution, I just improved it:
static long divisorSum(int n)
{
long sum = 0;
for (long i = 1; i <= n/2; ++i)
sum += i * (n / i);
sum += (n/2+1+n)*(n-n/2)/2; // It's a sum of an arithmetic progression
return sum;
}
For i > n/2 the expression i * (n / i) is simply i (because n/i = 1), so we can get the sum of all the numbers between n/2 + 1 to n by computing a sum of an arithmetic progression. It will run faster, although it is O(n) too.
You could do something like this O(n):
static long divisorSum(int n)
{
long sum = 0;
for (long i = 1; i <= n; ++i)
sum += i * (n / i);
return sum;
}
static void Main(string[] args)
{
int val = 129999;
Console.WriteLine(divisorSum(val));
Console.ReadLine();
}
Tests:
12999 => 8ms
129999 => 25ms
2147483647 => 18770ms (Max Int32 value)
int val = 129999;
int maxInt = int.MaxValue;
//val (129999)
var watch = System.Diagnostics.Stopwatch.StartNew();
Console.WriteLine(divisorSum(val));
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
Console.WriteLine(elapsedMs); //25ms
//MaxInt (2147483647)
watch = System.Diagnostics.Stopwatch.StartNew();
Console.WriteLine(divisorSum(maxInt));
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds; //18770ms
Console.WriteLine(elapsedMs);
Console.ReadLine();
There is no need to use a collection of sorts, since you sum everything up and don't need to think about duplicates. I don't think there is a way to get a solution for this which is a perfect O(n), but this is the closest I can think of:
int sum = 0;
for (int i = 1; i <= n; i++)
{
double sqrt = Math.Sqrt (i);
for (int j = 1; j <= sqrt; j++)
{
if (i % j == 0)
{
sum += j;
if (j != sqrt)
sum += i / j;
}
}
}
Divisors are pairs, so there isn't a need to go all the way to i every time (e.g 1 * 10, 10 * 1 are the same). You can go till the square-root of i (the 'mid-point'), and save time, hence it's not O(n^2), but not perfectly O(n).
Two (2 digit) numbers are written together, so they form one 4 digit number. This 4 digit number can be divided by the multiplication of this two numbers. The problem is that I have to find this numbers.
I wrote an algorithm and get 2 pair of these numbers.
1) 13 and 52, so 1352 can be divided by 13 * 52.
2) 17 and 34, so 1734 can be divided by 17 * 34.
My algorithm looks like this:
for (int i = 1010; i <= 9999; i++)
{
int mult = (i / 100) * (i % 100);
if ((i % 100) > 9 && i % mult == 0)
{
Console.WriteLine(i / 100 + " <--> " + i % 100);
}
}
Edit: with this algorithm (based on mentallurg answer) I find this numbers a bit faster
for (int i = 10; i < 99; i++)
{
for (int j = 10; j < 99; j++)
{
int mult = i * j;
int num = i * 100 + j;
if (num % mult == 0)
{
Console.WriteLine(i + " <--> " + j);
}
}
}
I am interested in how I can make this algorithm more efficient.
This is very efficient:
var query =
from x in Enumerable.Range(10, 90)
from n in Enumerable.Range(1, 10).TakeWhile(w => w * x < 100)
let v = x * (100 + n)
where v % (n * x * x) == 0
select new { x, y = n * x };
It computes all possible first digits. It then computes all of the possible second digits that are multiples of the first digit that are greater than zero and less than 100. It then produces the a candidate value at checks if it is divisible by the product of both digits.
It gives both of the possible answers.
Here's the equivalent using for loops:
for (int x = 10; x <= 99; x++)
{
for (int n = 1; x * n < 100; n++)
{
var j = x * n;
int v = x * 100 + j;
int d = x * j;
if (v % d == 0)
{
Console.WriteLine(x + " <--> " + j);
}
}
}
Supposed one of the pairs are a and b, and so the four digits number can be expressed as 100a + b. Do a little math
100a + b = m * a * b
Divided by a on both sides, we have
100 + b / a = m * b
We can conclude that
b can be divided by a, let's say (b == n * a);
b must be greater than a, since 101 is a prime. And it cannot be 3/7/9 times of a, since 103/107/109 are also primes, but let’s neglect this to make the for loop simpler. This can be easily handled in the inner loop of the following code.
So the for loop can be written like this
for (int a = 10; a < 50; a++)
{
for (int n = 2; n * a < 100; n++)
{
if ((100 + n) % (n * a) == 0)
Console.WriteLine(a + " " + n * a);
}
}
The number of iteration of the loop is reduced to a few dozens, from almost 10 thousand.
Use 2 nested cycles from 1 to 99 and you will avoid two division operations on each step.
What I want to know is how many numbers can be set if N bits are set to 1 out of 32bits.
Example lets try with 4 bits
//HowMany(1) = 4
//1000
//0100
//0010
//0001
//
//HowMany(2) = 6
//1001
//1010
//1100
//0110
//0101
//0011
public int HowMany(int bits)
{
....
}
I am trying to compute a precompute a dictionary for this but it takes ages:
var dict = new Dictionary<int, int>();
for (int i = 0; i <= Int32.MaxValue; i++)
{
var str = Convert.ToString(i, 2);
var count = str.Count(x => x == '1');
if (!dict .ContainsKey(count))
dict .Add(count, 0);
dict [count] += 1;
}
Easily: if size is n (32 in case of Int32) and we have exactly k bits set, we can represent
C(k, n) = n! / (k! * (n - k)!)
numbers, where C(k, n) stands for a binomial coefficient.
Edit: As dasblinkenlight's mentioned in the comments, 32! is a huge number which exceeds even long.MaxValue so, probably, a more practical formula is
C(k, n) = n * (n - 1) * ... * (n - k + 1) / k!
Possible C# implementation:
private static long HowMany(int k, int n = 32) {
long result = 1;
for (int i = 0; i < k; ++i)
result *= (n - i);
for (int i = 1; i <= k; ++i)
result /= i;
return result;
}
I am trying to calculate the nth digit of Pi without using Math.Pi which can be specified as a parameter.
I modified an existing algorithm, since I like to find the Nth digit without using string conversions or default classes.
This is how my algorithm currently looks like:
static int CalculatePi(int pos)
{
List<int> result = new List<int>();
int digits = 102;
int[] x = new int[digits * 3 + 2];
int[] r = new int[digits * 3 + 2];
for (int j = 0; j < x.Length; j++)
x[j] = 20;
for (int i = 0; i < digits; i++)
{
int carry = 0;
for (int j = 0; j < x.Length; j++)
{
int num = (int)(x.Length - j - 1);
int dem = num * 2 + 1;
x[j] += carry;
int q = x[j] / dem;
r[j] = x[j] % dem;
carry = q * num;
}
if (i < digits - 1)
result.Add((int)(x[x.Length - 1] / 10));
r[x.Length - 1] = x[x.Length - 1] % 10; ;
for (int j = 0; j < x.Length; j++)
x[j] = r[j] * 10;
}
return result[pos];
}
So far its working till digit 32, and then, an error occurs.
When I try to print the digits like so:
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
Console.WriteLine("{0} digit of Pi is : {1}", i, CalculatePi(i));
}
Console.ReadKey();
}
This I get 10 for the 32rd digit and the 85rd digit and some others as well, which is obviously incorrect.
The original digits from 27 look like so:
...3279502884.....
but I get
...32794102884....
Whats wrong with the algorithm, how can I fix this problem?
And can the algorithm still be tweaked to improve the speed?
So far it works right up until the cursor reaches digit 32. Upon which, an exception is thrown.
Rules are as follows:
Digit 31 is incorrect, because it should be 5 not a 4.
Digit 32 should be a 0.
When you get a 10 digit result you need to carry 1 over to the previous digit to change the 10 to a 0.
The code changes below will work up to ~ digit 361 when 362 = 10.
Once the program enters the 900's then there are a lot of wrong numbers.
Inside your loop you can do this by keeping track of the previous digit, only adding it to the list after the succeeding digit has been computed.
Overflows need to be handled as they occur, as follows:
int prev = 0;
for (int i = 0; i < digits; i++)
{
int carry = 0;
for (int j = 0; j < x.Length; j++)
{
int num = (int)(x.Length - j - 1);
int dem = num * 2 + 1;
x[j] += carry;
int q = x[j] / dem;
r[j] = x[j] % dem;
carry = q * num;
}
// calculate the digit, but don't add to the list right away:
int digit = (int)(x[x.Length - 1] / 10);
// handle overflow:
if(digit >= 10)
{
digit -= 10;
prev++;
}
if (i > 0)
result.Add(prev);
// Store the digit for next time, when it will be the prev value:
prev = digit;
r[x.Length - 1] = x[x.Length - 1] % 10;
for (int j = 0; j < x.Length; j++)
x[j] = r[j] * 10;
}
Since the digits are being updated sequentially one-by-one, one whole iteration later than previously, the if (i < digits - 1) check can be removed.
However, you need to add a new one to replace it: if (i > 0), because you don't have a valid prev value on the first pass through the loop.
The happy coincidence of computing only the first 100 digits means the above will work.
However, what do you suppose will happen when a 10 digit result follows a 9 digit one? Not good news I'm afraid, because the 1 with need carrying over to the 9 (the previous value), which will make it 10.
A more robust solution is to finish your calculation, then do a loop over your list going backwards, carrying any 10s you encounter over to the previous digits, and propagating any carries.
Consider the following:
for (int pos = digits - 2; pos >= 1; pos--)
{
if(result[pos] >= 10)
{
result[pos] -= 10;
result[pos - 1] += 1;
}
}