Combinatory issue due to Factorial overflow - java

I need a function which can calculate the mathematical combination of (n, k) for a card game.
My current attempt is to use a function based on usual Factorial method :
static long Factorial(long n)
{
return n < 2 ? 1 : n * Factorial(n - 1);
}
static long Combinatory(long n , long k )
{
return Factorial(n) / (Factorial(k) * Factorial(n - k));
}
It's working very well but the matter is when I use some range of number (n value max is 52 and k value max is 4), it keeps me returning a wrong value. E.g :
long comb = Combinatory(52, 2) ; // return 1 which should be actually 1326
I know that it's because I overflow the long when I make Factorial(52) but the range result I need is not as big as it seems.
Is there any way to get over this issue ?

Instead of using the default combinatory formula n! / (k! x (n - k)!), use the recursive property of the combinatory function.
(n, k) = (n - 1, k) + (n - 1, k - 1)
Knowing that : (n, 0) = 1 and (n, n) = 1.
-> It will make you avoid using factorial and overflowing your long.
Here is sample of implementation you can do :
static long Combinatory(long n, long k)
{
if (k == 0 || n == k )
return 1;
return Combinatory(n - 1, k) + Combinatory(n - 1, k - 1);
}
EDIT : With a faster iterative algorithm
static long Combinatory(long n, long k)
{
if (n - k < k)
k = n - k;
long res = 1;
for (int i = 1; i <= k; ++i)
{
res = (res * (n - i + 1)) / i;
}
return res;
}

In C# you can use BigInteger (I think there's a Java equivalent).
e.g.:
static long Combinatory(long n, long k)
{
return (long)(Factorial(new BigInteger(n)) / (Factorial(new BigInteger(k)) * Factorial(new BigInteger(n - k))));
}
static BigInteger Factorial(BigInteger n)
{
return n < 2 ? 1 : n * Factorial(n - 1);
}
You need to add a reference to System.Numerics to use BigInteger.

If this is not for a homework assignment, there is an efficient implementation in Apache's commons-math package
http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/ArithmeticUtils.html#binomialCoefficientDouble%28int,%20int%29
If it is for a homework assignment, start avoiding factorial in your implementation.
Use the property that (n, k) = (n, n-k) to rewrite your choose using the highest value for k.
Then note that you can reduce n!/k!(n-k)! to n * n-1 * n-2 .... * k / (n-k) * (n-k-1) ... * 1 means that you are multiplying every number from [k, n] inclusive, then dividing by every number [1,n-k] inclusive.
// From memory, please verify correctness independently before trusting its use.
//
public long choose(n, k) {
long kPrime = Math.max(k, n-k);
long returnValue = 1;
for(i = kPrime; i <= n; i++) {
returnValue *= i;
}
for(i = 2; i <= n - kPrime; i++) {
returnValue /= i;
}
return returnValue;
}
Please double check the maths, but this is a basic idea you could go down to get a reasonably efficient implementation that will work for numbers up to a poker deck.

The recursive formula is also known as Pascal's triangle, and IMO it's the easiest way to calculate combinatorials. If you're only going to need C(52,k) (for 0<=k<=52) I think it would be best to fill a table with them at program start. The following C code fills a table using this method:
static int64_t* pascals_triangle( int N)
{
int n,k;
int64_t* C = calloc( N+1, sizeof *C);
for( n=0; n<=N; ++n)
{ C[n] = 1;
for( k=n-1; k>0; --k)
{ C[k] += C[k-1];
}
}
return C;
}
After calling this with N=52, for example returns, C[k] will hold C(52,k) for k=0..52

Related

How to get the correct output in Modulo (10^9 + 7) format?

I am working on this code challenge:
Problem Description
Given 2 integers x and n, you have to calculate x
to the power of n, modulo 10^9+7 i.e. calculate (x^n) % (10^9+7).
In other words, you have to find the value when x is raised to the
power of n, and then modulo is taken with 10^9+7.
a%b means the remainder when a divides b. For instance, 5%3 = 2, as
when we divide 5 by 3, 2 is the remainder.
Note that 10^9 is also represented as 1e9.
Input format
One line of input containing two space separated
integers, x and n.
Output format Print the required answer.
Sample Input 1 100000000 2
Sample Output 1 930000007
Explanation 1 (10^8)^2 = 10^16
10^16 % (10^9+7) = 930000007
Constraints 0 <= x < 10^9
0 <= n < 10^5
Code
The following is my code:
import java.util.*;
class ModularExponentiation {
// NOTE: Please do not modify this function
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
int n = sc.nextInt();
int ans = modularExponentiation(x, n);
System.out.println(ans);
}
// TODO: Implement this method
static int modularExponentiation(int x, int n) {
int M = 1000000007;
long a = (long) Math.pow(x, n);
long b = a%M;
return (int)b;
}
}
When I run my code, it succeeds for the sample test case and an edge case, but fails for 3 base cases. How do I make my code succeed all test cases?
Does this work?
public static int modularExponentiation(int x, int n) {
int modulo = 1000000007;
if (n == 0) {
return 1;
} else if (n == 1) {
return x % modulo;
} else if (n == -1) {
return 1 / x;
}
int p = modularExponentiation(x, n >> 1);
long product = ((long) p * p) % modulo;
return (int) (product * modularExponentiation(x, n & 1) % modulo);
}
Key points:
Math.pow(x,n) suffers from overflow and we can't compensate that overflow relying on result only, that is why initial idea of Math.pow(x,n) % modulo produces wrong results
We may notice that (x * x) % modulo == (x % modulo) * (x % modulo) % modulo, and it is safe to use long here as intermediate result because x % modulo < modulo and modulo * modulo < 2^63 - 1
We need to reconstruct the process, but naive approach that x^n is a product of n x's is too slow - it has O(N) time complexity, however we may notice that x^2k == (x^k)^2 and x^(2k+1) == x * (x^k)^2 - so we may use either recursion here or loop to achieve O(LogN) time complexity
alternative loop solution:
public static int modularExponentiation(int x, int n) {
int modulo = 1000000007;
long product = 1;
long p = x;
while (n != 0) {
if ((n & 1) == 1) {
product = product * p % modulo;
}
p = (p * p % modulo);
n >>= 1;
}
return (int) product;
}
If you have problem in C++ then , you can use
const unsigned int Mod=1e9+7;

transforming an iterative function to recursive in java

i want to transform this function to recursive form could anyone help me thx
that function is to solve this stuff
X=1+(1+2)*2+(1+2+3)*2^2+(1+2+3+4)*2^3+ . . . +(1+2+3+4+. . . +n)*2^(n-1)
public static int calcX(int n) {
int x=1;
int tmp;
for(int i = 1 ; i <= n-1;i++) {
tmp=0;
for(int j = 1 ; j <= i + 1;j++) {
tmp+=j;
}
x+=tmp*Math.pow(2, i);
}
return x;
}
my attempt im new to recursive stuff
public static int calcXrecu(int n,int tmp,int i,int j) {
int x=1;
if(i <= n-1) {
if(j <= i) {
calcXrecu(n,tmp+j,i,j+1);
}
else {
x = (int) (tmp*Math.pow(2, i));
}
}
else {
x=1;
}
return x;
}
You have a sequence of sums which themselves are sums.
The nth term can be derived from the (n-1)th term like this:
a(n) = a(n-1) + (1+2+3+....+n) * 2^(n-1) [1]
and this is the recursive formula because it produces each term via the previous term.
Now you need another formula (high school math) for the sum of 1+2+3+....+n:
1+2+3+....+n = n * (n + 1) / 2 [2]
Now use [2] in [1]:
a(n) = a(n-1) + n * (n + 1) * 2^(n-2) [3]
so you have a formula with which you can derive each term from the previous term and this is all you need for your recursive method:
public static int calcXrecu(int n) {
if (n == 1) return 1;
return calcXrecu(n - 1) + n * (n + 1) * (int) Math.pow(2, n - 2);
}
This line:
if (n == 1) return 1;
is the exit point of the recursion.
Note that Math.pow(2, n - 2) needs to be converted to int because it returns Double.
In addition to #forpas answer, I also want to provide a solution using corecursion by utilizing Stream.iterate. This is obviously not a recursive solution, but I think it is good to know alternatives as well. Note that I use a Pair to represent the tuple of (index, value).
public static int calcXcorecu(final int n) {
return Stream.iterate(
Pair.of(1, 1), p -> {
final int index = p.getLeft();
final int prev = p.getRight();
final int next = prev + index * (index + 1) * (int) Math.pow(2, index - 2);
return Pair.of(index + 1, next);
})
// only need the n-th element
.skip(n)
.limit(1)
.map(Pair::getRight)
.findFirst()
.get();
}

Median of medians java implementation

I implemented Median of medians selection algorithm based on algs4 quickselect using the Wikipedia article, but my code doesn't work well:
1) it is said that median of medians finds kth largest element. However, my code finds kth smallest element.
2) my implementation runs 1-20 times slower than quickselect, but the median of medians algorithm should be asymptotically faster.
I've checked everything several times, but I cannot find the issue.
public class MedianOfMedians {
public static Comparable medianOfMedians(Comparable[] nums, int k) {
return nums[select(nums, 0, nums.length - 1, k)];
}
private static int select(Comparable[] nums, int lo, int hi, int k) {
while (lo < hi) {
int pivotIndex = pivot(nums, lo, hi);
int j = partition(nums, lo, hi, pivotIndex);
if (j < k) {
lo = j + 1;
} else if (j > k) {
hi = j - 1;
} else {
return j;
}
}
return lo;
}
private static int pivot(Comparable[] list, int left, int right) {
// for 5 or less elements just get median
if (right - left < 5) {
return partition5(list, left, right);
}
// otherwise move the medians of five-element subgroups to the first n/5 positions
for (int i = left; i <= right; i += 5) {
// get the median of the i'th five-element subgroup
int subRight = i + 4;
if (subRight > right) {
subRight = right;
}
int median5 = partition5(list, i, subRight);
exch(list, median5, (int) (left + Math.floor((i - left) / 5d)));
}
// compute the median of the n/5 medians-of-five
return select(list,
left,
(int) (left + Math.ceil((right - left) / 5d) - 1),
(int) (left + (right - left) / 10d));
}
private static int partition5(Comparable[] list, int lo, int hi) {
for (int i = lo; i <= hi; i++) {
for (int j = i; j > lo; j--) {
if (less(list[j - 1], list[j])) {
exch(list, j, j - 1);
}
}
}
return (hi + lo) / 2;
}
private static int partition(Comparable[] a, int lo, int hi, int pivotIndex) {
exch(a, lo, pivotIndex);
int i = lo;
int j = hi + 1;
Comparable v = a[lo];
while (true) {
while (less(a[++i], v) && i != hi) { }
while (less(v, a[--j]) && j != lo) { }
if (j <= i) break;
exch(a, i, j);
}
exch(a, j, lo);
return j;
}
private static void exch(Comparable[] nums, int i, int j) { }
private static boolean less(Comparable v, Comparable w) { }
}
JUnit test:
public class MedianOfMediansTest {
private final static int TESTS_COUNT = 100;
#org.junit.Test
public void test() {
// generate TESTS_COUNT arrays of 10000 entries from 0..Integer.MAX_VALUE
Integer[][] tests = generateTestComparables(TESTS_COUNT, 10000, 10000, 0, Integer.MAX_VALUE);
for (int i = 0; i < tests.length; i++) {
Integer[] array1 = Arrays.copyOf(tests[i], tests[i].length);
Integer[] array2 = Arrays.copyOf(tests[i], tests[i].length);
Integer[] array3 = Arrays.copyOf(tests[i], tests[i].length);
long time = System.nanoTime();
final int a = (Integer) MedianOfMedians.medianOfMedians(array1, 0);
long nanos_a = System.nanoTime() - time;
time = System.nanoTime();
final int b = (Integer) Quick.select(array2, 0);
long nanos_b = System.nanoTime() - time;
time = System.nanoTime();
Arrays.sort(array3);
final int c = array3[0];
long nanos_c = System.nanoTime() - time;
System.out.println("MedianOfMedians: " + a + " (" + nanos_a + ") " +
"QuickSelect: " + b + " (" + nanos_b + ") " +
"Arrays.sort: " + c + " (" + nanos_c + ")");
System.out.println(((double) nanos_a) / ((double) nanos_b));
Assert.assertEquals(c, a);
Assert.assertEquals(b, a);
}
}
public static Integer[][] generateTestComparables(int numberOfTests,
int arraySizeMin, int arraySizeMax,
int valueMin, int valueMax) {
Random rand = new Random(System.currentTimeMillis());
Integer[][] ans = new Integer[numberOfTests][];
for (int i = 0; i < ans.length; i++) {
ans[i] = new Integer[randInt(rand, arraySizeMin, arraySizeMax)];
for (int j = 0; j < ans[i].length; j++) {
ans[i][j] = randInt(rand, valueMin, valueMax);
}
}
return ans;
}
public static int randInt(Random rand, int min, int max) {
return (int) (min + (rand.nextDouble() * ((long) max - (long) min)));
}
}
1) it is said that median of medians finds kth largest element.
However, my code finds kth smallest element.
This is not strictly true. Any selection algorithm can find either smallest or largest element because that's essentially the same task. It depends on how you compare elements and how you partition them (and you can always do something like length - 1 - result later). Your code indeed seems to find the kth smallest element, which is by the way the most typical and intuitive way of implementing a selection algorithm.
2) my implementation runs 1-20 times slower than quickselect, but the
median of medians algorithm should be asymptotically faster.
Not just asymptotically faster. Asymptotically faster in the worst case. In the average case, both are linear, but MoM has higher constant factors. Since you generate your tests randomly, you are very unlikely to hit the worst case. If you used randomized quickselect, then for any input it's unlikely to hit the worst case, otherwise the probability will depend on the pivot selection algorithm used.
With that in mind, and the fact that median of medians has high constant factors, you should not expect it to perform better than quickselect! It might outperform sorting, though, but even then—those logarithmic factors in sorting aren't that large for small inputs (lg 10000 is about 13-14).
Take my MoM solution for a LeetCode problem, for example. Arrays.sort sometimes outperforms MoM for arrays with 500 million elements. In the best case it runs about twice faster, though.
Therefore, MoM is mostly of theoretical interest. I could imagine a practical use case when you need 100% guarantee of not exceeding some time limit. Say, some real-time system on an aircraft, or spacecraft, or nuclear reactor. The time limit is not very tight, but exceeding it even by one nanosecond is catastrophic. But it's an extremely contrived example, and I doubt that it's actually the way it works.
Even if you can find a practical use case for MoM, you can probably use something like Introselect instead. It essentially starts with quickselect, and then switches to MoM if things don't look good. But testing it would be a nightmare—how would you come up with a test that actually forces the algorithm to switch (and therefore test the MoM part), especially if it's randomized?
Your code looks fine overall, but I'd make some helper methods package-private or even moved them to another class to test separately because such things are very hard to get right. And you may not notice the effect if the result is right. I'm not sure that your groups-of-five code is 100% correct, for example. Sometimes you use right - left where I'd expect to see element count, which should be right - left + 1.
Also, I would replace those ceil/floor calls with pure integer arithmetic equivalents. That is, Math.floor((i - left) / 5d)) => (i - left) / 5, Math.ceil((right - left) / 5d) => (right - left + 4) / 5 (this is the part where I don't like the right - left thing, by the way, but I'm not sure if it's wrong).

Why is the Big-O of this algorithm N^2*log N

Fill array a from a[0] to a[n-1]: generate random numbers until you get one that is not already in the previous indexes.
This is my implementation:
public static int[] first(int n) {
int[] a = new int[n];
int count = 0;
while (count != n) {
boolean isSame = false;
int rand = r.nextInt(n) + 1;
for (int i = 0; i < n; i++) {
if(a[i] == rand) isSame = true;
}
if (isSame == false){
a[count] = rand;
count++;
}
}
return a;
}
I thought it was N^2 but it's apparently N^2logN and I'm not sure when the log function is considered.
The 0 entry is filled immediately. The 1 entry has probability 1 - 1 / n = (n - 1) / n of getting filled by a random number. So we need on average n / (n - 1) random numbers to fill the second position. In general, for the k entry we need on average n / (n - k) random numbers and for each number we need k comparisons to check if it's unique.
So we need
n * 1 / (n - 1) + n * 2 / (n - 2) + ... + n * (n - 1) / 1
comparisons on average. If we consider the right half of the sum, we see that this half is greater than
n * (n / 2) * (1 / (n / 2) + 1 / (n / 2 - 1) + ... + 1 / 1)
The sum of the fractions is known to be Θ(log(n)) because it's an harmonic series. So the whole sum is Ω(n^2*log(n)). In a similar way, we can show the sum to be O(n^2*log(n)). This means on average we need
Θ(n^2*log(n))
operations.
This is similar to the Coupon Collector problem. You pick from n items until you get one you don't already have. On average, you have O(n log n) attempts (see the link, the analysis is not trivial). and in the worst case, you examine n elements on each of those attempts. This leads to an average complexity of O(N^2 log N)
The algorithm you have is not O(n^2 lg n) because the algorithm you have may loop forever and not finish. Imagine on your first pass, you get some value $X$ and on every subsequent pass, trying to get the second value, you continue to get $X$ forever. We're talking worst case here, after all. That would loop forever. So since your worst case is never finishing, you can't really analyze.
In case you're wondering, if you know that n is always both the size of the array and the upper bound of the values, you can simply do this:
int[] vals = new int[n];
for(int i = 0; i < n; i++) {
vals[i] = i;
}
// fischer yates shuffle
for(int i = n-1; i > 0; i--) {
int idx = rand.nextInt(i + 1);
int t = vals[idx];
vals[idx] = vals[i];
vals[i] = t;
}
One loop down, one loop back. O(n). Simple.
If I'm not mistaken, the log N part comes from this part:
for(int i = 0; i < count; i++){
if(a[i] == rand) isSame = true;
}
Notice that I changed n for count because you know that you have only count elements in your array on each loop.

Binary search for square root [homework]

For an assignment I must create a method using a binary search to find the square root of an integer, and if it is not a square number, it should return an integer s such that s*s <= the number (so for 15 it would return 3). The code I have for it so far is
public class BinarySearch {
/**
* Integer square root Calculates the integer part of the square root of n,
* i.e. integer s such that s*s <= n and (s+1)*(s+1) > n
* requires n >= 0
*
* #param n number to find the square root of
* #return integer part of its square root
*/
private static int iSqrt(int n) {
int l = 0;
int r = n;
int m = ((l + r + 1) / 2);
// loop invariant
while (Math.abs(m * m - n) > 0) {
if ((m) * (m) > n) {
r = m;
m = ((l + r + 1) / 2);
} else {
l = m;
m = ((l + r + 1) / 2);
}
}
return m;
}
public static void main(String[] args) {
//gets stuck
System.out.println(iSqrt(15));
//calculates correctly
System.out.println(iSqrt(16));
}
}
And this returns the right number for square numbers, but gets stick in an endless loop for other integers. I know that the problem lies in the while condition, but I can't work out what to put due to the gap between square numbers getting much bigger as the numbers get bigger (so i can't just put that the gap must be below a threshold). The exercise is about invariants if that helps at all (hence why it is set up in this way). Thank you.
Think about it: Math.abs(m*m-n) > 0 is always true non-square numbers, because it is never zero, and .abs cannot be negative. It is your loop condition, that's why the loop never ends.
Does this give you enough info to get you going?
You need to change the while (Math.abs(m * m - n) > 0) to allow for a margin of error, instead of requiring it be exactly equal to zero as you do right now.
Try while((m+1)*(m+1) <= n || n < m * m)
#define EPSILON 0.0000001
double msqrt(double n){
assert(n >= 0);
if(n == 0 || n == 1){
return n;
}
double low = 1, high = n;
double mid = (low+high)/2.0;
while(abs(mid*mid - n) > EPSILON){
mid = (low+high)/2.0;
if(mid*mid < n){
low = mid+1;
}else{
high = mid-1;
}
}
return mid;}
As you can see above , you should simply apply binary search (bisection method)
and you can minimize Epsilon to get more accurate results but it will take more time to run.
Edit: I have written code in c++ (sorry)
As Ken Bloom said you have to have an error marge, 1. I've tested this code and it runs as expected for 15. Also you'll need to use float's, I think this algorithm is not possible for int's (although I have no mathematical proof)
private static int iSqrt(int n){
float l = 0;
float r = n;
float m = ((l + r)/2);
while (Math.abs(m*m-n) > 0.1) {
if ((m)*(m) > n) {
r=m;
System.out.println("r becomes: "+r);
} else {
l = m;
System.out.println("l becomes: "+l);
}
m = ((l + r)/2);
System.out.println("m becomes: "+m);
}
return (int)m;
}

Categories