Time efficient recursion for Magical Number - java

I was solving the Magical Number Problem where the number at nth position is the sum of the previous 3 numbers, minus 1. For example: 0 1 1 1 2 3 5 9 16.... and so on.
I solved it in 2 ways.
Code 1) Using Recursion
int magicNumber(int n){
int f = 0;
if (n == 1)
return 0;
else if (n > 1 && n <= 4)
return 1;
else
f = (magicNumber(n-1) + magicNumber(n-2) + magicNumber(n-3)) - 1;
return f;
}
Code 2) Using Array
void magicNumber(int n){
long arr[] = new long[100];
int i=1;
for(i = 1; i <= n; i++)
{
if(i==1)
arr[i] = 0;
else if(i>1&&i<=4)
arr[i] = 1;
else
arr[i] = (arr[i-1] + arr[i-2] + arr[i-3]) - 1;
}
System.out.println("Result is : "+arr[n]);
}
Code 1 works fine when I provide a small integer number to the program, but it hangs with the input of bigger integer numbers and Code 2 runs fine without any problem.
So I need your suggestions, how can I improve the performance of the recursion program Code 1?

You can speed up your recursion like this:
int magicNumber2(int n, int a, int b, int c){
if (n <= 1) return a;
return magicNumber2(n - 1, b, c, a + b + c - 1);
}
int magicNumber(int n) {
magicNumber2(n, 0, 1, 1);
}

You're experiencing delay for higher numbers because each recursive call ends up in 3 more recursive calls. Hence the time rises exponentially. Try this approach:
Maintain a lookup table. Here I have an array magic_num[100] with all it's elements initialized to -1.
int magicNumber(int n){
if(n == 1)
{
magic_num[n] = 0;
return 0;
}
else if(n>1 && n<=4)
{
magic_num[n] = 1;
return 1;
}
else if(magic_num[n] == -1)
{
magic_num[n] = magicNumber(n-1) + magicNumber(n-2) + magicNumber(n-3) - 1;
return magic_num[n];
}
else
return magic_num[n];
}

Related

Stackoverflow Error in Staircase Problem when step size is greater than 3

I'm trying to solve the staircase problem in java with a method that gets the number of stairs (n) and the maximum step size (maxStep). Somehow it works until step size is > 3 after that I get a Stackoverflow error but I don't know why that is.
public static int climbStairs(int n, int maxStep) {
if (n == 0 || n == 1) {
return 1;
} else if (n == 2) {
return 2;
} else {
int count = 0;
for (int i = 1; i <= maxStep; i++) {
count += climbStairs(n - i, maxStep);
}
return count;
}
}
Try this code hope it will work.
public static int climbStairs2(int n, int maxStep) {
if (n == 0 || n == 1) {
return 1;
} else if (n < maxStep) {
return n;
} else {
int count = 0;
for (int i = 1; i <= maxStep; i++) {
count += climbStairs2(n - i, maxStep);
}
return count;
}
}
You don't check whether the maxstep is smaller than the step count. This means that after a while, the i<=maxstep can be > n, which results in negative n for the next recursion. If it once turns to the negatives, it will recurse infinitely. To fix it, just check for n<=maxstep or n<=0.
Example of your 'bad' code: Try inputs 5,4: it will start the method with n=
5
4
3
-1
-2

split string into groups with given condition

Given a String only made of only 2 letters a,b. Now the task is to split this string into exactly 3 groups such that the number of a's in each group must be same. Then find how many such groups are possible.
Example:
Input:
ababab
Possiblities:
ab ab ab
Output:
1 as we can create only 1 such group, with single a in each group
Example:
Input:
ababbabbaaba
Possiblities:
aba bbabba aba
abab babba aba
ababb abba aba
Output:3
as we can create 3 such possible groups with 2 a's in each group.
Now I came across below code that is solving this task.
public static int findGroups(String input) {
int numberOfAs = 0;
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == 'a')
numberOfAs++;
}
int n = input.length();
if (numberOfAs == 0) {
return (n - 1) * (n - 2) / 2;
}
if (numberOfAs % 3 != 0)
return 0;
int numberOfAsInAGroup = numberOfAs / 3;
int lastAIn1stGroup = 0; // last occurrence of A in 1st group
int firstAIn2ndGroup = 0; // 1st occurrence of A in 2nd group
int lastAIn2ndGroup = 0; // last occurrence of A in 2nd group
int firstAIn3rdGroup = 0; // 1st occurrence of A in 3rd group
int aCount = 0;
for (int i = 0; i < n; i++) {
if (input.charAt(i) == 'a') {
aCount++;
if (aCount == numberOfAsInAGroup) {
lastAIn1stGroup = i;
} else if (aCount == numberOfAsInAGroup + 1) {
firstAIn2ndGroup = i;
}
if (aCount == 2 * numberOfAsInAGroup) {
lastAIn2ndGroup = i;
} else if (aCount == 2 * numberOfAsInAGroup + 1) {
firstAIn3rdGroup = i;
break;
}
}
}
int betweenSecondAndFirstGroup = firstAIn2ndGroup - lastAIn1stGroup;
int betweenThirdAndSecondGroup = firstAIn3rdGroup - lastAIn2ndGroup;
return betweenSecondAndFirstGroup * betweenThirdAndSecondGroup;
}
This code is working perfectly finw without any errors. But I am trying to understand for past several days what formulas are being used in this code to solve this task.
Part - 1:
if (numberOfAs == 0) {
return (n - 1) * (n - 2) / 2;
}
After searching in google for several hrs I found the explanation here - number-of-ways-of-distributing-n-identical-objects-among-r-groups:
Part - 2:
int betweenSecondAndFirstGroup = firstAIn2ndGroup - lastAIn1stGroup;
int betweenThirdAndSecondGroup = firstAIn3rdGroup - lastAIn2ndGroup;
return betweenSecondAndFirstGroup * betweenThirdAndSecondGroup;
I am not able to understand this part 2 formula, how this is solving the given problem, is there any explanation as mentioned for part 1.
Also just curious to know, is there any alternate version to solve this task without using formulas like this?
It can be done in linear time.
public class Main {
public static int Nth_A_After(String s, int n, int index){
for(int i = index + 1; i < s.length(); i++) {
if(s.charAt(i) == 'a'){
n--;
if(n == 0) return i;
}
}
return -1;
}
public static void main(String[] args) {
String s = "ababab";
int count = 0;
for(int i = 0; i < s.length(); i++) if(s.charAt(i) == 'a') count++;
if(count % 3 != 0) {
System.out.println("Impossible!");
return;
}
int pos = count / 3;
int firstEnd = Nth_A_After(s, pos, -1);
int secondBegin = Nth_A_After(s, 1, firstEnd);
int secondEnd = Nth_A_After(s, pos - 1, secondBegin);
int thirdBegin = Nth_A_After(s, 1, secondEnd);
int leftDif = secondBegin - firstEnd;
int rightDif = thirdBegin - secondEnd;
if(leftDif > 1) leftDif++;
if(rightDif > 1) rightDif++;
System.out.println(leftDif * rightDif);
}
}
I guess there is a problem in your example ababab, since there is more than just one possibility:
1. a ba bab
2. a bab ab
3. ab a bab
4. ab ab ab
The code you're looking at is finding the boundary As of each group, then is counting the number of spaces the dividing line between the groups could go. This depends on the number of Bs separating the groups of As, since these don't affect the count.
The answer is the number of possible dividing lines on the left, times the number on the right.
AA|B|B|AABAA <-- in this example there are 3 on the left
AABBAA|B|AA <-- and 2 on the right
for a total of 6.
AA|BBAA|BAA
AA|BBAAB|AA
AAB|BAA|BAA
AAB|BAAB|AA
AABB|AA|BAA
AABB|AAB|AA

Find a pair of natural numbers who have the least energy among all pairs having sum of n

There is a natural number n. You have to find a pair of natural numbers x, y whose sum is n and also have the least energy among other pair having the sum n.
Energy(x) = sum of all digits of x
Total Energy = Energy(x) + Energy(y)
1 <= n <= 10^9
For eg,
n = 10000
A few pairs:
5000 + 5000 -> Energy = 10
1000 + 9000 -> Energy = 10
9999 + 1 -> Energy = 37
2999 + 7001 -> Energy = 37
So possible answers are:
(5000, 5000), (1000, 9000) etc
I have tried the solution noted above so far but it is not an optimized approach
I will loop from 1 to n-1 and and try all pairs and check their sum of digits but it will take too much time for big numbers.
e.g.
n= 50
1,49--> energy 14
2,48--> energy 14
3,47--> energy 14
4,46--> energy 14
5,45--> energy 14
.
.
.
.
10,40-->energy 5
(Edited) After some thought, I arrived at the following solution. Would appreciate if somebody can come up with a better solution
public int sum(int n) {
String s = String.valueOf(n);
if (isNonZeroOnlyOne(n)) {
int num = getNonZeroNo(n);
if (num == 1)
return 10;
return num;
}
return calculateEnergy(s);
}
private int calculateEnergy(String s) {
int sum = 0;
for(int i=0; i<s.length(); i++)
sum += s.charAt(i) - '0';
return sum;
}
private int getNonZeroNo(int n) {
String s = String.valueOf(n);
for(int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (c != '0')
return c-'0';
}
return '0';
}
private boolean isNonZeroOnlyOne(int n) {
String s = String.valueOf(n);
int count = 0;
for(int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (c != '0')
count++;
if (count > 1)
return false;
}
return true;
}
It's simple.
if n is of type 10^x then the answer is 10. otherwise answer is the sum of digits of n.
The idea here is to break down the number into a pair containing digits less than that are present in n. if you break down into smaller digits then sum remains the same as the original number.
example for 7= 1-6,2-5,3-4.
for a number like 100, 1000....
digit 1 can't be broken down into further pairs, so we try to make 10 as the sum of digit so that the sum becomes n.
like for 10=5-5,2-8,3-7
100=20-80,40-60
for other numbers, like 123
it can be broken into 100-23, 120-3, 111-12... all will give you sum 6. which is the sum of digits of the original number.
if you try to break down into further pairs like 80-43, 52-71, you will see that the digit sum increases as you broken down to a number containing digits which is higher than those are present in n. like 8 4,5,7 are greater than 3.
The least energy can be derived by a simple formula.
1) Given N > 100, the pair can be N-100 and 100 , and the energy will be same as the energy of N.
eg : N = 500 ; Pair = 400 and 100 ; Energy = 5
2) N >=10 and N <=100 , pair = N-10 and 10
eg : N = 50 ; Pair = 40 and 10 ; Energy = 5
3) N >=2 and N <=10 , pair = N-1 and 1
eg : N = 5 ; Pair = 4 and 1 ; Energy = 5
I spent more than 1 hour on this problem. What should be answer for n = 1? So I think n should be greater than 1. I am assuming n > 1.
So brute-force solution won't work here because n is huge enough. So you need more optimized solution. You need to think think about how many times you have to carry 1 in the sum to make n. It is at most 9 times!
If you have some basic idea with digit-dp(Dynamic Programming) then this problem is easy. Try to place all possible digit on a place of n and take minimum energy among them. This problem is easy when you fully understand digit-dp technique. You can learn it from here and here.
For practice, you can find a lot of problems here (Dynamic programming section).
For your references, I wrote this code just now and it is working properly. Hope you can use this as a reference.
#include <bits/stdc++.h>
using namespace std;
const string INF_STRING = "9999999";
const int INF_INT = 9999999;
pair<string, int> INF = make_pair(INF_STRING, INF_INT);
int nod;
int digits[10];
int num_of_digits(int a) {
int cnt = 0;
while(a) {
digits[cnt] = a % 10;
a = a / 10;
cnt++;
}
return cnt;
}
pair<string, int> dp[10][2][2][2];
pair<string, int> solve(int ind, int carry, bool is1, bool is2) {
if(ind >= nod) {
if(carry != 0 || !is1 || !is2) return INF;
return make_pair("", 0);
}
pair<string, int> &ret = dp[ind][carry][is1][is2];
if(ret.second != -1) return ret;
ret = INF;
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++) {
int s = (i + j + carry);
pair<string, int> cur = INF;
if(s % 10 == digits[ind]) {
cur = solve(ind + 1, s / 10, is1 || (i > 0? 1:0), is2 || (j > 0? 1:0));
}
if((cur.second + i + j) < ret.second) {
ret.second = cur.second + i + j;
ret.first = cur.first + (char)(i + '0');
}
}
}
return ret;
}
int stringToInt(string num) {
stringstream ss;
ss<<num;
int ret;
ss >> ret;
return ret;
}
int main() {
int i, t, cases = 1, j, k, pos;
int n;
scanf("%d", &n);
nod = num_of_digits(n);
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 2; j++) {
dp[i][j][0][0] = make_pair(INF_STRING, -1);
dp[i][j][0][1] = make_pair(INF_STRING, -1);
dp[i][j][1][0] = make_pair(INF_STRING, -1);
dp[i][j][1][1] = make_pair(INF_STRING, -1);
}
}
pair<string, int> res = solve(0, 0, 0, 0);
string num1_str = res.first;
int num1 = stringToInt(num1_str);
int num2 = n - num1;
printf("Minimum Energy: %d\n", res.second);
printf("Num1 = %d, Num2 = %d\n", num1, num2);
return 0;
}
/*
Input:
10000
Output:
Minimum energy: 10
Num1 = 1000, Num2 = 9000
*/
Here is the answer in javascript in simple way.
function calculateEnergy(n) {
let e = 0
while(n > 0) {
e += n % 10
n = Math.floor(n / 10)
}
return e
}
function countMinEnergy(n) {
let minE = n
let i = 1
while(i <= n/2) {
let e = calculateEnergy(i) + calculateEnergy(n - i)
minE = e < minE ? e : minE
i++
}
return minE
}
countMinEnergy(4325)
Here is scala solution
object LeastEnergyPair extends App {
private def getCountOfPair(array: Array[Int],sum: Int): mutable.Set[(Int, Int)] = {
val seen = mutable.Set[Int]()
val out = mutable.Set[(Int,Int)]()
array map { x =>
val target = sum - x
if (seen.contains(target) || target*2 == sum)
out += ((Math.min(x,target),Math.max(x,target)))
else
seen += x
}
println(out)
out
}
private def sum(i:Int): Int = i.toString.toCharArray.map(_.asDigit).sum
def findLeastEnergyPair(a: mutable.Set[(Int,Int)]): (Int,Int) = {
var min = Int.MaxValue
var minPair = (0,0)
a.foreach {
case (i,j) =>
if (sum(i) + sum(j) < min) {
min = sum(i) + sum(j)
minPair = (i,j)
println(s"$min ----- $minPair")
}
}
minPair
}
println(findLeastEnergyPair(getCountOfPair((1 to 10000).toArray, 10000)))
}
The below logic will cover all scenarios
if (N%10 == 0) {
x1= (N/10);
x2 = N-x1
}else{
x1 = N-10;
x2 = 10;
}

Finding primitive roots using Java

I am trying to get the first primitive root of a prime number:
private static int GetPrime(int factors[], int modul) {
for (int i = 2; i < modul; i++) {
int j = 0;
while (j < factors.length) {
int power = (modul - 1) / factors[j];
long g = (long) Math.pow(i, power);
long mod = g % modul;
if (mod == 1) {
j++;
break;
} else if (j + 1 == factors.length) {
return i;
}
j++;
}
}
return 0;
}
As parameters i have prime factors of number (factors) and prime number (modul). I tried to implement function for finding the first prime root, for some numbers it works, but for other it fails. Forexample it gives the correct answer for 23 which is 5, but for 71 it fails, instead of 7 it gives 3. I can't figure out what is wrong.
Basically formula is n^((modul-1)/factor) % modul, if for one of factors the reminder for each n is 1, then n is not a prime root.

difficulty with fibonacci function

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];
}

Categories

Resources