Fibonacci sequence pruning using java - java

Here is my implementation of the fibonacci sequence using java
/**
* Returns nth fibonacci number
*/
public class fib {
public static void main(String[] args){
System.out.println(fibonacci(12));
}
public static int fibonacci(int n) {
if (n == 0){
return 0;
} else if (n == 1){
return 1;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
}
But visualization of this method using recursion made me think it would be a lot faster.
Here is a visualization of fib(5). http://imgur.com/a/2Rgxs
But this got my thinking, notice at the bottom when we bubble up from the bottom of the recursive path we calculate fib(2), fib(3) and fib(4) but then we recalculate fib(3) on the very top right branch. So I was thinking when we are bubbling back up why not save fib(3) calculated from the left branch so we don't do any calculations on the right branch like my method currently does, like a hashtable while coming back up.
My question is, how do I implement this idea?

When you want to add the HashMap and stay with your original approach, try this:
static HashMap<Integer, Integer> values = new HashMap<Integer, Integer>();
public static void main(String[] args){
values.put(0, 0);
values.put(1, 1);
System.out.println(fibonacci(12));
}
public static int fibonacci(int n) {
if (values.containsKey(n)){
return values.get(n);
} else {
int left = values.containsKey(n - 1) ? values.get(n - 1) : fibonacci(n - 1);
values.put(n - 1, left);
int right = values.containsKey(n - 2) ? values.get(n - 2) : fibonacci(n - 2);
values.put(n - 2, right);
return left + right;
}
}
This approach could be very fast if you call it more often because the fibonacci results are already stored in the values (for sure this could also be done with other approaches):
public static void main(String[] args){
values.put(0, 0);
values.put(1, 1);
System.out.println(fibonacci(12));
System.out.println(fibonacci(11));
System.out.println(fibonacci(10));
}

For a fast calculation, you do not need recursion at all - just shift the intermediate results
public static int fibonacci(int n) {
if (n == 0) {
return 0;
} else {
int npp = 0; // pre-previous number
int np = 1; // previouse number
int r = 1; // current number, eventually the result
for (int i = 2; i <= n; i++) {
r = np + npp;
npp = np;
np = r;
}
return r;
}
}

In order to avoid repeated calculations, you can use dynamic programming. BTW, this is not a memory optimized solution, but it can be faster than the recursive one.
public static int fibonacci(int n)
{
int f[] = new int[n+1];
for (int i = 0; i <= n; i++) {
if(i == 0 || i == 1) {
f[i] = i;
}
else {
f[i] = f[i-1] + f[i-2];
}
}
return f[n];
}

Related

perfect squares leetcode - recursive solution with memoization

Trying to solve this problem with recursion and memoization but for input 7168 I'm getting wrong answer.
public int numSquares(int n) {
Map<Integer, Integer> memo = new HashMap();
List<Integer> list = fillSquares(n, memo);
if (list == null)
return 1;
return helper(list.size()-1, list, n, memo);
}
private int helper(int index, List<Integer> list, int left, Map<Integer, Integer> memo) {
if (left == 0)
return 0;
if (left < 0 || index < 0)
return Integer.MAX_VALUE-1;
if (memo.containsKey(left)) {
return memo.get(left);
}
int d1 = 1+helper(index, list, left-list.get(index), memo);
int d2 = 1+helper(index-1, list, left-list.get(index), memo);
int d3 = helper(index-1, list, left, memo);
int d = Math.min(Math.min(d1,d2), d3);
memo.put(left, d);
return d;
}
private List<Integer> fillSquares(int n, Map<Integer, Integer> memo) {
int curr = 1;
List<Integer> list = new ArrayList();
int d = (int)Math.pow(curr, 2);
while (d < n) {
list.add(d);
memo.put(d, 1);
curr++;
d = (int)Math.pow(curr, 2);
}
if (d == n)
return null;
return list;
}
I'm calling like this:
numSquares(7168)
All test cases pass (even complex cases), but this one fails. I suspect something is wrong with my memoization but cannot pinpoint what exactly. Any help will be appreciated.
You have the memoization keyed by the value to be attained, but this does not take into account the value of index, which actually puts restrictions on which powers you can use to attain that value. That means that if (in the extreme case) index is 0, you can only reduce what is left with one square (1²), which rarely is the optimal way to form that number. So in a first instance memo.set() will register a non-optimal number of squares, which later will get updated by other recursive calls which are pending in the recursion tree.
If you add some conditional debugging code, you'll see that map.set is called for the same value of left multiple times, and with differing values. This is not good, because that means the if (memo.has(left)) block will execute for cases where that value is not guaranteed to be optimal (yet).
You could solve this by incorporating the index in your memoization key. This increases the space used for memoization, but it will work. I assume you can work this out.
But according to Lagrange's four square theorem every natural number can be written as the sum of at most four squares, so the returned value should never be 5 or more. You can shortcut the recursion when you get passed that number of terms. This reduces the benefit of using memoization.
Finally, there is a mistake in fillSquares: it should add n itself also when it is a perfect square, otherwise you'll not find solutions that should return 1.
Not sure about your bug, here is a short dynamic programming Solution:
Java
public class Solution {
public static final int numSquares(
final int n
) {
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
int j = 1;
int min = Integer.MAX_VALUE;
while (i - j * j >= 0) {
min = Math.min(min, dp[i - j * j] + 1);
++j;
}
dp[i] = min;
}
return dp[n];
}
}
C++
// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <cstdint>
#include <vector>
#include <algorithm>
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
#define MAX INT_MAX
using ValueType = std::uint_fast32_t;
struct Solution {
static const int numSquares(
const int n
) {
if (n < 1) {
return 0;
}
static std::vector<ValueType> count_perfect_squares{0};
while (std::size(count_perfect_squares) <= n) {
const ValueType len = std::size(count_perfect_squares);
ValueType count_squares = MAX;
for (ValueType index = 1; index * index <= len; ++index) {
count_squares = std::min(count_squares, 1 + count_perfect_squares[len - index * index]);
}
count_perfect_squares.emplace_back(count_squares);
}
return count_perfect_squares[n];
}
};
int main() {
std::cout << std::to_string(Solution().numSquares(12) == 3) << "\n";
return 0;
}
Python
Here we can simply use lru_cache:
class Solution:
dp = [0]
#functools.lru_cache
def numSquares(self, n):
dp = self.dp
while len(dp) <= n:
dp += min(dp[-i * i] for i in range(1, int(len(dp) ** 0.5 + 1))) + 1,
return dp[n]
Here are LeetCode's official solutions with comments:
Java: DP
class Solution {
public int numSquares(int n) {
int dp[] = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// bottom case
dp[0] = 0;
// pre-calculate the square numbers.
int max_square_index = (int) Math.sqrt(n) + 1;
int square_nums[] = new int[max_square_index];
for (int i = 1; i < max_square_index; ++i) {
square_nums[i] = i * i;
}
for (int i = 1; i <= n; ++i) {
for (int s = 1; s < max_square_index; ++s) {
if (i < square_nums[s])
break;
dp[i] = Math.min(dp[i], dp[i - square_nums[s]] + 1);
}
}
return dp[n];
}
}
Java: Greedy
class Solution {
Set<Integer> square_nums = new HashSet<Integer>();
protected boolean is_divided_by(int n, int count) {
if (count == 1) {
return square_nums.contains(n);
}
for (Integer square : square_nums) {
if (is_divided_by(n - square, count - 1)) {
return true;
}
}
return false;
}
public int numSquares(int n) {
this.square_nums.clear();
for (int i = 1; i * i <= n; ++i) {
this.square_nums.add(i * i);
}
int count = 1;
for (; count <= n; ++count) {
if (is_divided_by(n, count))
return count;
}
return count;
}
}
Java: Breadth First Search
class Solution {
public int numSquares(int n) {
ArrayList<Integer> square_nums = new ArrayList<Integer>();
for (int i = 1; i * i <= n; ++i) {
square_nums.add(i * i);
}
Set<Integer> queue = new HashSet<Integer>();
queue.add(n);
int level = 0;
while (queue.size() > 0) {
level += 1;
Set<Integer> next_queue = new HashSet<Integer>();
for (Integer remainder : queue) {
for (Integer square : square_nums) {
if (remainder.equals(square)) {
return level;
} else if (remainder < square) {
break;
} else {
next_queue.add(remainder - square);
}
}
}
queue = next_queue;
}
return level;
}
}
Java: Most efficient solution using math
Runtime: O(N ^ 0.5)
Memory: O(1)
class Solution {
protected boolean isSquare(int n) {
int sq = (int) Math.sqrt(n);
return n == sq * sq;
}
public int numSquares(int n) {
// four-square and three-square theorems.
while (n % 4 == 0)
n /= 4;
if (n % 8 == 7)
return 4;
if (this.isSquare(n))
return 1;
// enumeration to check if the number can be decomposed into sum of two squares.
for (int i = 1; i * i <= n; ++i) {
if (this.isSquare(n - i * i))
return 2;
}
// bottom case of three-square theorem.
return 3;
}
}

Calculate log base 2 recursion

i'm creating recursion method that calculate Log base 2. for log*(1) = should be 0. log*(4) = should be 2. but my method only print out zero and i couldn't figure out the problem.can some one help me?
public static int logCalculator(double n) {
if (n == 1) {
return 0;
} else {
return 1 + logCalculator(n * n);
}
}
This will work for base 2 logs
public static int logCalculator1(double n) {
if (n < 2)
return 0;
return 1 + logCalculator1(n / 2);
}
NOTE: this will round down always and with high numbers is inaccurate, in addition you can make it for all bases like this:
public static int logCalculator(int base, double n) {
if (base > 0) {
if (n < base) {
return 0;
} else {
return 1 + logCalculator(base, (int)(n / base));
}
} return 0;
}

Improve time complexity of this code

Can anyone here please help me to reduce the time complexity of this code:
public static int a(int number) {
if ((number == 0) || (number == 1))
return number;
else
return a(number - 1) + a(number - 2);
}
public static void main(String[] args) {
System.out.print("Enter the count of Fibonacci series: ");
int cap = new Scanner(System.in).nextInt();
System.out.println("Output: ");
for (int i = 1; i <= cap; i++){
System.out.printf("%d\n", a(i));
}
}
You can store previously calculated values, so if you try calculate fibonnaci(100) you don't calculate fibonacci(50) about 100 times.
Pseudo code:
dictA = {}
a(n):
if n in dictA:
return dictA[n]
else if n <= 1:
return n
else:
val = a(n-1) + a(n-2)
dictA[n] = val
return val
It is quite simple to add some cache, where you will store already calculated values. If you want exactly the recursive algorithm the idea will be the same - just check in the beginning of routine if the value already calculated. If yes - return it from cache, else - start calculate (do not forget to save it after calculation ended).
public class Fibbonaci {
public static long calc(int n) {
List<Integer> cache = new ArrayList<>();
cache.add(1);
cache.add(2);
for (int i = 2; i < n; i++) {
cache.add(cache.get(i - 1) + cache.get(i - 2));
}
return cache.get(n - 1);
}
public static void main(String[] args) {
IntStream.range(1, 10)
.forEach(n -> System.out.println("Fibb " + n + " = " + calc(n)));
}
}

Getting a runtime error against an online programming judge

So here is my code for the 3n+1 problem on UVa. It runs perfectly on my PC in Eclipse AFAIK, however, I keep getting a runtime error against the UVa judge. Unfortunately, the judge does not tell me what inputs it uses, nor provide any information beyond "RuntimeException" when it fails. This is the same structure as the ACM's ICPC, for the curious.
I am pretty sure that the recursion shall not overflow the stack as the maximum cycle length of all numbers from 1 to 1000000 is only 525. Also, the cache of 1000000 integers shall be only 4Mb large.
package Collatz;
import java.util.Arrays;
import java.util.Scanner;
class Main{
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int[] cache = buildCache(1000000);
while (in.hasNextLine()) {
Scanner line = new Scanner(in.nextLine());
if (!line.hasNextInt()) continue;
int a = line.nextInt();
int b = line.nextInt();
int c = a;
int d = b;
if (c > d) {
int temp = c;
c = d;
d = temp;
}
int max = 0;
for (int i = c - 1; i <= d - 1; i++) {
max = Math.max(max, cache[i]);
}
System.out.format("%d %d %d\n", a, b, max);
line.close();
}
in.close();
}
public static int[] buildCache(int n) {
int[] cache = new int[n];
Arrays.fill(cache, 0);
cache[0] = 1;
for (int i = 1; i < n; i++) {
search(i + 1, cache);
}
return cache;
}
public static int search(long i, int[] cache) {
int n = cache.length;
if (i == 1) {
return 1;
} else if (i <= n && cache[(int)(i - 1)] > 0) {
return cache[(int)(i - 1)];
} else {
long j = (i % 2 == 1) ? (3 * i + 1) : (i / 2);
int result = search(j, cache) + 1;
if (i <= n) {
cache[(int)(i - 1)] = result;
}
return result;
}
}
}
OK. I finally found the problem. It is the package statement. The program is accepted after removing it... A bit mistake for me when copy-paste code from my IDE to submission form.. But there are some interesting discussions here and thank everyone!
The logic here will overflow the stack. It goes searching for the next number in the sequence before caching the result of the function on the current one.
int result = search(j, cache) + 1;
if (i <= n) {
cache[(int)(i - 1)] = result;
}
return result;

Sum of List<Integer> recursively

Hello fellow programmers.
I am having a very silly problem.. I'm supposed to sum all the integers in a List, recursively. I know that there is an easier way to do this, and I actually made that method too (see class below). But the meaning of this assignment is that I have to split the list up into 2 halves and then calculate the sum recursively on both halves, and last I just return half1 + half2.
The problem is that the advanced method does not return the sum of all values. Can anyone please help me?
The method sum is the simple method. Summer(Summarize in danish) is the more advanced method.
package opgave1;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class BinærSøgning {
public static void main(String[] args) {
Random random = new Random();
int tal = 3;
List<Integer> liste = new ArrayList<Integer>();
for (int i = 0; i < 10; i++)
liste.add(random.nextInt(10));
Collections.sort(liste);
System.out.println(liste);
// System.out.println(binærSøgning(liste, 0, tal));
System.out.println(summer(liste, 0));
}
public static int binærSøgning(List<Integer> liste, int start, int find) {
if (liste.size() > 0) {
int midt = liste.size() / 2;
if (liste.get(midt) == find)
return start + midt;
else if (liste.size() > 1) {
if (find < liste.get(midt))
return binærSøgning(liste.subList(0, midt), start, find);
else
return binærSøgning(liste.subList(midt + 1, liste.size()), start + midt + 1, find);
}
}
return -1;
}
public static int sum (List<Integer> list, int i)
{
if (i == list.size())
return 0;
else
return list.get(i) + sum(list, i+1);
}
public static int summer(List<Integer> list, int start){
int right = 0;
int left = 0;
if(start == list.size()){
return 0;
} else {
int mid = list.size() / 2;
if(start < mid){
left += list.get(start) + summer(list.subList(0, mid), start+1);
} else if(mid < list.size()){
right += list.get(mid) + summer(list.subList(mid+1, list.size()), mid+1);
}
}
return right + left;
}
}
Ii's much easier with two base cases, there is no need for an extra 'start' parameter if you use sublists. (Because it's homework, I won't fill in the details.)
public static int summer(List<Integer> list) {
//base 1
if (list.size() == 0) {
}
//base 2
else if (list.size() == 1) {
}
else
{
//no need for if statements now!
int left = summer(list.sublist(/* */))
int right = summer(list.sublist(/* */))
return left + right;
}
}
Are you sure that you have to split the list? Usually, when you get this task for homework, the meaning is something like:
public static int sum(List<Integer> l,int start) {
if (start==l.size()) return 0;
return l.get(start)+sum(l,start+1);
}
You are missing out elements of list when you are sending start+1 in the recursion.
left += list.get(start) + summer(list.subList(0, mid), start+1);
You should rather send
left += list.get(0) + summer(list.subList(1, mid), 0);
and
right += list.get(mid) + summer(list.subList(mid+1, list.size()), 0);
I dont see the need to sending any start value. Every recursion should take the 0 in place of start.
I think it can be solved in a simpler way, by keeping track of both the first and last index of the range, like this:
public static int sum(List<Integer> list, int i, int j) {
if (i == j)
return list.get(i);
int half = (i + j) / 2;
return sum(list, i, half) + sum(list, half + 1, j);
}
It's called like this:
List<Integer> list = Arrays.asList(1, 2, 3);
System.out.println(sum(list, 0, list.size()-1));
It will work fine for non-empty lists. If the list is empty, you'll need to check it before calling sum.
First of all, you don't need to cut the list in half if all you need to do is use recursion. The sum of the elements of a list is the sum of its first element + the sum of all the elements of the rest of the list.
Second, your method is too complex. The sum of the elements of the list is 0 if the list is empty, the unique element is it contains 1 element, and the sum of the results of the method applied to the two sublists if it contains more than 1. You don't need any start argument.
This should get you started.
EDIT: since Oscar Lopez gave you the answer, but I find it too complex, here's mine:
public static int sum(List<Integer> list) {
if (list.isEmpty()) {
return 0;
}
else if (list.size() == 1) {
return list.get(0);
}
else {
int half = list.size() / 2;
return sum(list.subList(0, half)) + sum(list.subList(half, list.size()));
}
}
I am wondering a reason of getting a "half" of the List.The solution for the question is the one and only:
public int sum_list(List<Integer> list) {
if (list == null || list.isEmpty()) {
return 0;
}
return list.remove(0) + sum_list(list);
}
import java.util.*;
public class SumListByRecursion {
public static int sumByRec(List<Integer> list) {
int size = list.size();
if(size > 0) {
return list.get(0) + sumByRec(list.subList(1, size));
}
return 0;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println("List:"+" "+list);
int sum = sumByRec(list);
System.out.println("Sum of the list:"+" "+sum);
}
}
You can use this method for sum all ement of given list.
public static Integer sumOfList(List<Integer> list){
try {
return list.get(0) + sumOfList(list.subList(1, list.size()));
}catch (Exception e) {
return 0;
}
}

Categories