I've written the code for finding the binomial coefficient in recursive form:
public int binom(int n, int k)
{
if (k==n || k==0)
return 1;
else return binom(n-1,k-1) + binom(n-1, k);
}
How can I rewrite this code in iterative form instead of recursive form?
Instead of building the entire Pascal triangle up to the n-th row (memory usage grows quadratically with n), we can simply focus on the row itself, and use constant memory.
Let's find a relationship between consecutive terms on the same row on Pascal's triangle:
Thus we can iteratively generate the terms from nC0 = 1:
public static int binom(int n, int k)
{
int value = 1;
// need to be careful here - can't just use *= due to integer division
for (int i = 0; i < k; i++)
value = (value * (n - i)) / (i + 1);
return value;
}
public int binom(int n, int k)
{
int C[][] = new int[n+1][k+1];
int i, j;
int min;
// Caculate value of Binomial Coefficient in bottom up manner
for (i = 0; i <= n; i++)
{
min = (i<k)? i: k;
for (j = 0; j <= min; j++)
{
// Base Cases
if (j == 0 || j == i)
C[i][j] = 1;
// Calculate value using previosly stored values
else
C[i][j] = C[i-1][j-1] + C[i-1][j];
}
}
return C[n][k];
}
Related
I have the following programm calculating the binomial coefficient of two integers. But I want to change the programm, that it calculates and saves only the necessary coefficients for the solution.
The problem is that I have really no idea how to it, right now.
The Code
public static long binomialIteration(int n, int k)
{
if(k<0 || n<k)
{
return 0;
}
long[][] h= new long[n+1][n+1];
for(int i=0; i<=n; i++)
{
h[i][0]=h[i][i]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=0; j<=i; j++)
{
h[i][j] = (j==0 ? 0: h[i-1][j-1]) + (i == j ? 0 : h[i-1][j]);
}
}
return h[n][k];
}
Do you want to keep your code afterall?
Because you can also compute the binominal coefficient recursively, which would reduce your function to these 4 lines:
static long binomi(int n, int k) {
if ((n == k) || (k == 0))
return 1;
else
return binomi(n - 1, k) + binomi(n - 1, k - 1);
}
What about this Code from this site
private static long binomial(int n, int k)
{
if (k>n-k)
k=n-k;
long b=1;
for (int i=1, m=n; i<=k; i++, m--)
b=b*m/i;
return b;
}
You don't say which coefficients youi need. If you need C(N,n) for some fixed N, you could translate the C code below, which uses a one dimensional array.
After the call, C[n] will hold the binomial coefficient C(N,n) for 0<=m<=N, as long as N is at most 66 -- if you need bigger N you will need to use an integral type with more bits.
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;
k = n;
while( --k>0)
{ C[k] += C[k-1];
}
}
return C;
}
I need to count all the divisors for every number in the range 1 to n. I have written down below an implementation for, given an integer num, it counts the number of divisors of num. Its complexity is O(sqrt(n)). So over all complexity comes out to be O(n * sqrt(n)). Can it be reduced? If YES, then can you give an algorithm for that?
CODE :
public static int countDivisors(int num)
{
int limit = (int)Math.sqrt(num);
int count = 2;
for(int i = 2 ; i <= limit ; i++)
{
if(num % i == 0)
{
count++;
if(num / i != i)
{
count++;
}
}
}
return count;
}
PS:
This function will be called n times.
You can improve upon the naive approach using kind of a generalized Sieve of Eratosthenes. Instead of just marking the number as composite also store its first divisor that you found (I do this in the function computeDivs below).
class Main
{
// using Sieve of Eratosthenes to factorize all numbers
public static int[] computeDivs(int size) {
int[] divs = new int[size + 1];
for (int i = 0; i < size + 1; ++i) {
divs[i] = 1;
}
int o = (int)Math.sqrt((double)size);
for (int i = 2; i <= size; i += 2) {
divs[i] = 2;
}
for (int i = 3; i <= size; i += 2) {
if (divs[i] != 1) {
continue;
}
divs[i] = i;
if (i <= o) {
for (int j = i * i; j < size; j += 2 * i) {
divs[j] = i;
}
}
}
return divs;
}
// Counting the divisors using the standard fomula
public static int countDivisors(int x, int[] divs) {
int result = 1;
int currentDivisor = divs[x];
int currentCount = 1;
while (currentDivisor != 1) {
x /= currentDivisor;
int newDivisor = divs[x];
if (newDivisor != currentDivisor) {
result *= currentCount + 1;
currentDivisor = newDivisor;
currentCount = 1;
} else {
currentCount++;
}
}
if (x != 1) {
result *= currentCount + 1;
}
return result;
}
public static int countAllDivisors(int upTo) {
int[] divs = computeDivs(upTo + 1);
int result = 0;
for (int i = 1; i <= upTo; ++i) {
result += countDivisors(i, divs);
}
return result;
}
public static void main (String[] args) throws java.lang.Exception {
System.out.println(countAllDivisors(15));
}
}
You can also see the code executed on ideone here.
In short I use the sieve to compute the biggest prime factor for each number. Using this I can compute the factor decomposition of every number very efficiently (and I use this in countDivisors).
It is hard to compute the complexity of the sieve but a standard estimate is O(n * log(n)). Also I am pretty confident it is not possible to improve on that complexity.
You can do much better than O(n.sqrt(n)) by using simple iteration. The code is in C++, but you can easily get the idea.
#include <iostream>
#include <vector>
using namespace std;
void CountDivisors(int n) {
vector<int> cnts(n + 1, 1);
for (int i = 2; i <= n; ++i) {
for (int j = i; j <= n; j += i) {
cnts[j]++;
}
}
for (int i = 1; i <= n; ++i) {
cout << cnts[i] << " \n"[i == n];
}
}
int main() {
CountDivisors(100);
return 0;
}
Running time is n/1 + n/2 + n/3 + n/4 + ... + n/n which can be approximated by O(nH(n)), where H(n) is the harmonic series. I think the value is not bigger than O(nlog(n)).
Using iteration is OK for relatively small numbers. As soon as the number of divisors is getting bigger (over 100-200), the iteration is going to take a significant amount of time.
A better approach would be to count the number of divisors with help of prime factorization of the number.
So, express the number with prime factorization like this:
public static List<Integer> primeFactorizationOfTheNumber(long number) {
List<Integer> primes = new ArrayList<>();
var remainder = number;
var prime = 2;
while (remainder != 1) {
if (remainder % prime == 0) {
primes.add(prime);
remainder = remainder / prime;
} else {
prime++;
}
}
return primes;
}
Next, given the prime factorization, express it in the exponent form, get exponents and add 1 to each of them. Next, multiply resulting numbers. The result will be the count of divisors of a number. More on this here.
private long numberOfDivisorsForNumber(long number) {
var exponentsOfPrimeFactorization = primeFactorizationOfTheNumber(number)
.stream()
.collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()))
.values();
return exponentsOfPrimeFactorization.stream().map(n -> n + 1).reduce(1L, Math::multiplyExact);
}
This algorithm works very fast. For me, it finds a number with 500 divisors within less than a second.
I'm supposed to change this recursive function, into an iterative function...
int rFib(int n)
{ //assumes n >= 0
if(n <= 1)
return n;
else
return (rFib(n-1) + rFib(n-2));
}
But I'm drawing a blank on the mathematical view of this... I would appreciate any assistance. I was able to get the other 3 functions, but I just can't seem to figure out the math of this one.
public static int fib(int n)
{
int theFib = 1;
while(n > 1)
{
theFib = n - 1;
n = n + n - 2;
}
System.out.println(theFib);
return theFib;
}
The next number in the Fibonacci sequence is the sum of the last two numbers, so you'll need to remember the last two numbers.
In pseudo code, since you should do some of the homework yourself:
n1 = 0
n2 = 1
loop
n = n1 + n2
n1 = n2
n2 = n
end loop
I'll leave it to you to limit the looping.
You can find an example here.
The code in question:
public class FibonacciIterative {
public static int fib(int n) {
int prev1=0, prev2=1;
for(int i=0; i<n; i++) {
int savePrev1 = prev1;
prev1 = prev2;
prev2 = savePrev1 + prev2;
}
return prev1;
}
}
It does not really matter which direction (up or down) you count. The challenge is to deal with the limits properly.
Using dynamic programming technique:
static int fib(int n) {
int[] fibs = new int[n + 1];
for (int i = 0; i <= n; i++) {
if (i <= 1) {
fibs[i] = i;
} else {
fibs[i] = fibs[i - 1] + fibs[i - 2];
}
}
return fibs[n];
}
I am doing programming project from book about data structures and algorithms and I need to implement insertion into ordered array using binary search.
My initial implementation for this using linear approach is:
public void insert(long value) { // put element into array
int j;
for (j = 0; j < nElems; j++) // find where it goes
if (a[j] > value) // (linear search)
break;
for (int k = nElems; k > j; k--) // move bigger ones up
a[k] = a[k-1];
a[j] = value; // insert it
nElems++; // increment size
} // end insert()
But, I am stuck when I tried to create something similar using binary search approach.
Here is what I did:
public void insert(long value) {
int lowerBound = 0;
int upperBound = nElems-1;
int curIn;
while(lowerBound < upperBound) {
curIn = (lowerBound + upperBound) / 2;
if(arr[curIn]>value && arr[curIn-1] < value) {
for(int k=nElems; k>curIn; k--)
arr[k] = arr[k-1];
arr[curIn] = value;
} else {
if(arr[curIn] > value)
upperBound = curIn-1;
else
lowerBound = curIn+1;
}
}
} // end insert()
I think my main mistake is the following :
I don't have any logic which handles empty array case.
Give me some advice please. I just started to learn this stuff about a week ago, so some explanation would be great.
Thank you in advance, Nick.
During the loop you can keep a loop invariant(insert position always in interval [lowerBound upperBound]).
So when arr[curIn] > value, halve the interval to [lowerBound curIn]
when arr[curIn] <= value, halve the interval to [curIn+1 upperBound]
After the loop, lowerBound is the position to insert.
//Assume arr, nElems are declared somewhere else and enough space to insert...
public void insert(long value) {
int lowerBound = 0;
int upperBound = nElems;
int curIn;
while(lowerBound < upperBound) {
curIn = (lowerBound+upperBpund)/2;
if(arr[curIn] > value) {
upperBound = curIn;
} else {
lowerBound = curIn+1;
}
}
//note lowerBound may equal nElems, it works anyway
for(int k = nElems; k > lowerBound; k--) {
arr[k] = arr[k-1];
}
arr[lowerBound] = value;
nElems++;
}
- This is my find() method using Binary Search algorithm:
It works just as you would expect it to. No problems at all.
public int find(long searchKey) {
int lowerBound = 0;
int upperBound = nElems - 1;
int currentIndex;
while(true) {
currentIndex = (lowerBound + upperBound) / 2;
if(a[currentIndex] == searchKey)
return currentIndex; // found it!
else if(lowerBound > upperBound)
return nElems; // can't find it
else { // so then divide range
if(a[currentIndex] < searchKey)
lowerBound = currentIndex + 1; // it's in upper half
else
upperBound = currentIndex - 1; // it's in lower half
} // end else divide range
} // end while loop
} // end find() method
Here's the original insert() method using linear search. Pretty straightforward, right?
public void insert(long value) { // put element into array
int j;
for(j=0; j<nElems; j++) // find where it goes
if(a[j] > value) // (linear search)
break;
for(int k=nElems; k>j; k--) // move bigger ones up
a[k] = a[k-1];
a[j] = value; // insert it
nElems++; // increment size
} // end insert()
I need to modify the insert() method to use the binary search algorithm of the find() method. Here's what I came up with so far. Obviously there's something wrong with it, but I can't seem to find the problem. It doesn't work at all, i.e. no insertions are performed:
public int insertBS(long value) {
int lowerBound = 0;
int upperBound = nElems - 1;
int curIn;
while(true) {
curIn = (lowerBound + upperBound) / 2;
if(a[curIn] == value)
return curIn;
else if(lowerBound > upperBound)
return nElems;
else {
if(a[curIn] < value)
lowerBound = curIn + 1;
else
upperBound = curIn - 1;
}
for(int k=nElems; k>curIn; k--) // move bigger one up
a[k] = a[k-1];
a[curIn] = value;
nElems++;
}
}
Language: Java
Using ordered array.
well, it's obvious why the value isn't inserted, it's because you never inserted the value. Once you found the index of the position to insert you simply return from the function without doing anything.
Um, why not just CALL your find function?
public int insertBS(long value) {
int curIn = find(value); // find where it goes (binary search)
for(int k=nElems; k>curIn; k--) // move bigger one up
a[k] = a[k-1];
a[j] = value; // insert it
nElems++; // increment size
}
This way, when you optimize/change your find function, your insert function will go faster, too!
As a side note, I think your find function will not give you expected behavior, as written. If you have a list of [0,1,4,5,9] and I search for 7, I will get an index of nElems (5), which could be misinterpreted as the values at indexes 0 to 4 are all less than 7. Seems a little wonky.
You need to perform the binary search to find the insertion index before moving elements. In your last code snippet, you are attempting to use the variable curIn to move elements inside your while loop before your binary search has finished. Try moving the for loop outside of the while loop.
int lowerBound = 0;
int upperBound = nElems-1;
int pos = 0;
if(value < a[0])
pos=0;
else if(nElems>0 && value>a[upperBound])
pos=nElems;
else
{
while(nElems>1)
{
int j = (lowerBound + upperBound ) / 2;
if(upperBound - lowerBound ==0)
{
pos = lowerBound+1;
break; // found it
}
else if(upperBound - lowerBound ==1)
{
pos=upperBound; //lo encontre
break;
}
else // divide range
{
if(a[j] < value)
lowerBound = j + 1; // it's in upper half
else
upperBound = j - 1; // it's in lower half
} // end else divide range
}
}
for(int k=nElems; k>pos; k--) // move higher ones up
a[k] = a[k-1];
a[pos] = value; // insert it
nElems++; // increment size