I am trying to create and return a BigInteger list that computes a given integer, n, as a sum of Fibonacci numbers in descending order. For example, if given the integer n = 8000, the result would return [6765, 987, 233, 13, 2].
I have written a code that computes the Fibonacci numbers into a list while the said number is less than n, but I'm not quite how to implement the rest.
The fib function seems too complicated to me. Just compute next element from sum of two last elements:
public static List<BigInteger> fib(BigInteger n) {
List<BigInteger> fibs = new ArrayList<>(asList(ONE, ONE));
for (BigInteger last = ONE; last.compareTo(n) < 0; ) {
last = last.add(fibs.get(fibs.size() - 2));
fibs.add(last);
}
return fibs;
}
Then go backwards in the list and keep elements which fit into sum:
public static void main(String[] args) {
BigInteger n = BigInteger.valueOf(8000);
List<BigInteger> fib = fib(n);
BigInteger remaining = n;
for (int i = fib.size() - 1; i >= 0; i--) {
if (fib.get(i).compareTo(remaining) > 0) {
fib.remove(i);
} else {
remaining = remaining.subtract(fib.get(i));
}
}
Collections.reverse(fib);
System.out.println(fib);
}
If you print fibs you'll realize that you loop adds two 1's, so you should remove the {fibs.add(BigInteger.ONE); fibs.add(BigInteger.ONE);} line.
Now that you have all the Fibonacci number's, you start at the end of the list, and subtract numbers from n as long as the value doesn't go negative.
Easiest way to iterate a list backwards, is to reverse the list and iterate it normally.
Collections.reverse(fibs);
for (BigInteger fib : fibs) {
...
}
You can also do it without reversing the list, by using a ListIterator to iterate backwards.
for (ListIterator<BigInteger> iter = fibs.listIterator(fibs.size()); iter.hasPrevious(); ) {
BigInteger fib = iter.previous();
...
}
To find the numbers you can subtract from n, just keep a running value of what still need to be reduced, i.e. how much of the original b remains.
BigInteger remain = n;
for (BigInteger fib : fibs) {
if (fib.compareTo(remain) <= 0) { // if (fib <= remain)
remain = remain.subtract(fib); // remain -= fib;
}
}
Add the values you subtract to a result list, and you're done.
Related
Requirement : There's an input List and an input shift no.
The first line contains two space-separated integers that denote :
n, the number of integers, and
d, the number of left rotations to perform.
The second line contains space-separated integers that describe arr[].
Constraints
1 <= n <= 10^5
1 <= d <= n
1 <= arr[i] <= 10^6
Sample Input
5 , 4
1 2 3 4 5
Sample Output
5 1 2 3 4
I have written this code which is working correctly but getting timeout while large operation. So I need to optimize my code to successfully run all the test cases. How to achieve that.
public static List<Integer> rotateLeft(int d, List<Integer> arr) {
int size = arr.size();
while(d>0) {
int temp = arr.get(0);
for(int i = 0; i<size; i++){
if(i != size-1){
arr.set(i,arr.get(i+1));
} else {
arr.set(i,temp);
}
}
d--;
}
return arr;
}
Failing for this input :
n = 73642
d = 60581
And a huge Integer List of size 73642.
Instead of using nested loops, this can be done in one loop. The final index of an element at index i after n shifts, can be calculated as (i + n) % listLength, this index can be used to populate a shifted list. Like this:
import java.util.*;
class HelloWorld {
public static void main(String[] args) {
List<Integer> arr = Arrays.asList(1,2,3,4,5);
System.out.println(rotateLeft(4, arr));
}
public static List<Integer> rotateLeft(int d, List<Integer> arr) {
List<Integer> rotatedList = new ArrayList<>(arr.size());
int i=0;
for(i=0; i< arr.size(); i++) {
int rotatedElementIndex = ((i+d) % arr.size());
rotatedList.add(arr.get(rotatedElementIndex));
}
return rotatedList;
}
}
Never liked hackerrank puzzles. What does "and a huge Integer array" mean? May we create a new list or we need to modify existing one? If we ought to modify existing one why our method is not void?
If we may create new list the optimal solution would be creating new Integer[] array and call System.arraycopy() twice.
In case of inline modifications the solution is:
public static List<Integer> rotateLeft(int d, List<Integer> arr) {
int i = 0, first = arr.get(0);
int n = arr.size();
while (true) {
int source = (i + d) % n;
if (source == 0) {
arr.set(i, first);
break;
}
arr.set(i, arr.get(source));
i = source;
}
return arr;
}
For an in-place solution:
reverse the subarrays arr[0, d) and arr[d, n) in-place. This is done by swapping the elements in symmetric pairs.
reverse the whole array.
E.g., abcdefghijk, d=4
abcd|efghijk -> dcba|kjihgfe -> efghijk|abcd
Write a function:
class Solution{
public int solution(int[] A);
}
that, given an array A of N integers, returns the smallest positive integer(greater than 0)
that does not occur in A.
For example, given A = [1,3,6,4,1,2], the function should return 5.
Given A = [1,2,3], the function should return 4.
Given A = [-1, -3], the function should return 1.
Write an efficient algorithm for the following assumptions.
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [-1,000,000..1,000,000].
I wrote the following algorithm in Java:
public class TestCodility {
public static void main(String args[]){
int a[] = {1,3,6,4,1,2};
//int a[] = {1,2,3};
//int b[] = {-1,-3};
int element = 0;
//checks if the array "a" was traversed until the last position
int countArrayLenght = 0;
loopExtern:
for(int i = 0; i < 1_000_000; i++){
element = i + 1;
countArrayLenght = 0;
loopIntern:
for(int j = 0; j < a.length; j++){
if(element == a[j]){
break loopIntern;
}
countArrayLenght++;
}
if(countArrayLenght == a.length && element > 0){
System.out.println("Smallest possible " + element);
break loopExtern;
}
}
}
}
It does the job but I am pretty sure that it is not efficient. So my question is, how to improve this algorithm so that it becomes efficient?
You should get a grasp on Big O, and runtime complexities.
Its a universal construct for better understanding the implementation of efficiency in code.
Check this website out, it shows the graph for runtime complexities in terms of Big O which can aid you in your search for more efficient programming.
http://bigocheatsheet.com/
However, long story short...
The least amount of operations and memory consumed by an arbitrary program is the most efficient way to achieve something you set out to do with your code.
You can make something more efficient by reducing redundancy in your algorithms and getting rid of any operation that does not need to occur to achieve what you are trying to do
Point is to sort your array and then iterate over it. With sorted array you can simply skip all negative numbers and then find minimal posible element that you need.
Here more general solution for your task:
import java.util.Arrays;
public class Main {
public static int solution(int[] A) {
int result = 1;
Arrays.sort(A);
for(int a: A) {
if(a > 0) {
if(result == a) {
result++;
} else if (result < a){
return result;
}
}
}
return result;
}
public static void main(String args[]){
int a[] = {1,3,6,4,1,2};
int b[] = {1,2,3};
int c[] = {-1,-3};
System.out.println("a) Smallest possible " + solution(a)); //prints 5
System.out.println("b) Smallest possible " + solution(b)); //prints 4
System.out.println("c) Smallest possible " + solution(c)); //prints 1
}
}
Complexity of that algorithm should be O(n*log(n))
The main idea is the same as Denis.
First sort, then process but using java8 feature.
There are few methods that may increase timings.(not very sure how efficient java 8 process them:filter,distinct and even take-while ... in the worst case you have here something similar with 3 full loops. One additional loop is for transforming array into stream). Overall you should get the same run-time complexity.
One advantage could be on verbosity, but also need some additional knowledge compared with Denis solution.
import java.util.function.Supplier;
import java.util.stream.IntStream;
public class AMin
{
public static void main(String args[])
{
int a[] = {-2,-3,1,2,3,-7,5,6};
int[] i = {1} ;
// get next integer starting from 1
Supplier<Integer> supplier = () -> i[0]++;
//1. transform array into specialized int-stream
//2. keep only positive numbers : filter
//3. keep no duplicates : distinct
//4. sort by natural order (ascending)
//5. get the maximum stream based on criteria(predicate) : longest consecutive numbers starting from 1
//6. get the number of elements from the longest "sub-stream" : count
long count = IntStream.of(a).filter(t->t>0).distinct().sorted().takeWhile(t->t== supplier.get()).count();
count = (count==0) ? 1 : ++count;
//print 4
System.out.println(count);
}
}
There are many solutions with O(n) space complexity and O(n) type complexity. You can convert array to;
set: array to set and for loop (1...N) check contains number or not. If not return number.
hashmap: array to map and for loop (1...N) check contains number or not. If not return number.
count array: convert given array to positive array count array like if arr[i] == 5, countArr[5]++, if arr[i] == 1, countArr[1]++ then check each item in countArr with for loop (1...N) whether greate than 1 or not. If not return it.
For now, looking more effective algoritm like #Ricola mentioned. Java solution with O(n) time complexity and O(1) space complexity:
static void swap(final int arr[], final int i,final int j){
final int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
static boolean isIndexInSafeArea(final int arr[], final int i){
return arr[i] > 0 && arr[i] - 1 < arr.length && arr[i] != i + 1 ;
}
static int solution(final int arr[]){
for (int i = 0; i < arr.length; i++) {
while (isIndexInSafeArea(arr,i) && arr[i] != arr[arr[i] - 1]) {
swap(arr, i, arr[i] - 1);
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] != i + 1) {
return i+1;
}
}
return arr.length + 1;
}
I have a program that sums the common elements of two arrays. For that I used two for loops and if I have three then I could use three for loops. But how to sum the common elements of n number of arrays where n is coming during run time.
I don't know how to change the number of loops during run time or is there any other relevant concept for this ?
Here is the code I've tried for summing twoarrays:
import java.util.Scanner;
public class Sample {
public static void main(String... args)
{
Scanner sc=new Scanner(System.in);
int arr1[]={1,2,3,4,5},arr2[]={4,5,6,7,8},sum=0;
for (int i=0;i<arr1.length;i++)
{
for (int j=0;j<arr2.length;j++)
{
if (arr1[i]==arr2[j])
{
sum+=(arr1[i]);
}
}
}
}
}
There can be different implementation for that. You can use the following approach. Here is the pseudo code
use a 2D array to store the array. if the number of array is n and size is m then the array will be input[n][m]
Use a ArrayList commonItems to store the common items of. Initiate it with the elements of input[0]
Now iterate through the array for i = 1 to n-1. compare with every input[i], store only the common items of commonItems and input[i] at each step. You can do it by converting the input[i] into a list and by using retainAll method.
At the end of the iteration the commonItem list will contains the common numbers only. Now sum the value of this list.
There is actually a more general method, that also answers the question "how to change the number of loops during run time?".
The general question
We are looking for a way to implement something equivalent to this:
for (i1 = 0; i1 < k1; i1++) {
for (i2 = 0; i2 < k2; i2++) {
for (i3 = 0; i3 < k3; i3++) {
...
for (in = 0; in < kn; in++) {
f(x1[i1], x2[i2], ... xn[in]);
}
...
}
}
}
where, n is given at runtime and f is a function taking a list of n parameters, processing the current n-tuple.
A general solution
There is a general solution, based on the concept of recursion.
This is one implementation that produces the desired behavior:
void process(int idx, int n, int[][] x, int[] k, Object[] ntuple) {
if (idx == n) {
// we have a complete n-tuple,
// with an element from each of the n arrays
f(ntuple);
return;
}
// this is the idx'th "for" statement
for (int i = 0; i < k[idx]; i++) {
ntuple[idx] = x[idx][i];
// with this recursive call we make sure that
// we also generate the rest of the for's
process(idx + 1, n, x, k, ntuple);
}
}
The function assumes that the n arrays are stored in a matrix x, and the first call should look like this:
process(0, n, x, k, new Object[n]);
Practical considerations
The solution above has a high complexity (it is O(k1⋅k2⋅..⋅kn)), but sometimes it is possible to avoid going until the deepest loop.
Indeed, in the specific problem mentioned in this post (which requires summing common elements across all arrays), we can skip generating some tuples e.g. if already x2[i2] ≠ x1[i1].
In the recursive solution, those situations can easily be pruned. The specific code for this problem would probably look like this:
void process(int idx, int n, int[][] x, int[] k, int value) {
if (idx == n) {
// all elements from the current tuple are equal to "value".
// add this to the global "sum" variable
sum += value;
return;
}
for (int i = 0; i < k[idx]; i++) {
if (idx == 0) {
// this is the outer "for", set the new value
value = x[0][i];
} else {
// check if the current element from the idx'th for
// has the same value as all previous elements
if (x[idx][i] == value) {
process(idx + 1, n, x, k, value);
}
}
}
}
Assuming that the index of the element is not important: a[1] = 2 and a[5] = 2, you only need two nested loops.
First you need to put n-1 arrays in a list of sets. Then loop over nth array and check if each element exists in all of the sets in the list. If it does exist then add to total.
I need a task about finding Fibonacci Sequence for my independent project in Java. Here are methods for find.
private static long getFibonacci(int n) {
switch (n) {
case 0:
return 0;
case 1:
return 1;
default:
return (getFibonacci(n-1)+getFibonacci(n-2));
}
}
private static long getFibonacciSum(int n) {
long result = 0;
while(n >= 0) {
result += getFibonacci(n);
n--;
}
return result;
}
private static boolean isInFibonacci(long n) {
long a = 0, b = 1, c = 0;
while (c < n) {
c = a + b;
a = b;
b = c;
}
return c == n;
}
Here is main method:
long key = getFibonacciSum(n);
System.out.println("Sum of all Fibonacci Numbers until Fibonacci[n]: "+key);
System.out.println(getFibonacci(n)+" is Fibonacci[n]");
System.out.println("Is n2 in Fibonacci Sequence ?: "+isInFibonacci(n2));
Codes are completely done and working. But if the n or n2 will be more than normal (50th numbers in Fib. Seq.) ? Codes will be runout. Are there any suggestions ?
There is a way to calculate Fibonacci numbers instantaneously by using Binet's Formula
Algorithm:
function fib(n):
root5 = squareroot(5)
gr = (1 + root5) / 2
igr = 1 - gr
value = (power(gr, n) - power(igr, n)) / root5
// round it to the closest integer since floating
// point arithmetic cannot be trusted to give
// perfect integer answers.
return floor(value + 0.5)
Once you do this, you need to be aware of the programming language you're using and how it behaves. This will probably return a floating point decimal type, whereas integers are probably desired.
The complexity of this solution is O(1).
Yes, one improvement you can do is to getFibonacciSum(): instead of calling again and again to isInFibonacci which re-calculates everything from scratch, you can do the exact same thing that isInFibonacci is doing and get the sum in one pass, something like:
private static int getFibonacciSum(int n) {
int a = 0, b = 1, c = 0, sum = 0;
while (c < n) {
c = a + b;
a = b;
sum += b;
b = c;
}
sum += c;
return sum;
}
Well, here goes my solution using a Map and some math formulas. (source:https://www.nayuki.io/page/fast-fibonacci-algorithms)
F(2k) = F(k)[2F(k+1)−F(k)]
F(2k+1) = F(k+1)^2+F(k)^2
It is also possible implement it using lists instead of a map but it is just reinventing the wheel.
When using Iteration solution, we don't worry about running out of memory, but it takes a lot of time to get fib(1000000), for example. In this solution we may be running out of memory for very very very very big inputs (like 10000 billion, idk) but it is much much much faster.
public BigInteger fib(BigInteger n) {
if (n.equals(BigInteger.ZERO))
return BigInteger.ZERO;
if (n.equals(BigInteger.ONE) || n.equals(BigInteger.valueOf(2)))
return BigInteger.ONE;
BigInteger index = n;
//we could have 2 Lists instead of a map
Map<BigInteger,BigInteger> termsToCalculate = new TreeMap<BigInteger,BigInteger>();
//add every index needed to calculate index n
populateMapWhitTerms(termsToCalculate, index);
termsToCalculate.put(n,null); //finally add n to map
Iterator<Map.Entry<BigInteger, BigInteger>> it = termsToCalculate.entrySet().iterator();//it
it.next(); //it = key number 1, contains fib(1);
it.next(); //it = key number 2, contains fib(2);
//map is ordered
while (it.hasNext()) {
Map.Entry<BigInteger, BigInteger> pair = (Entry<BigInteger, BigInteger>)it.next();//first it = key number 3
index = (BigInteger) pair.getKey();
if(index.remainder(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
//index is divisible by 2
//F(2k) = F(k)[2F(k+1)−F(k)]
pair.setValue(termsToCalculate.get(index.divide(BigInteger.valueOf(2))).multiply(
(((BigInteger.valueOf(2)).multiply(
termsToCalculate.get(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE)))).subtract(
termsToCalculate.get(index.divide(BigInteger.valueOf(2)))))));
}
else {
//index is odd
//F(2k+1) = F(k+1)^2+F(k)^2
pair.setValue((termsToCalculate.get(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE)).multiply(
termsToCalculate.get(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE)))).add(
(termsToCalculate.get(index.divide(BigInteger.valueOf(2))).multiply(
termsToCalculate.get(index.divide(BigInteger.valueOf(2))))))
);
}
}
// fib(n) was calculated in the while loop
return termsToCalculate.get(n);
}
private void populateMapWhitTerms(Map<BigInteger, BigInteger> termsToCalculate, BigInteger index) {
if (index.equals(BigInteger.ONE)) { //stop
termsToCalculate.put(BigInteger.ONE, BigInteger.ONE);
return;
} else if(index.equals(BigInteger.valueOf(2))){
termsToCalculate.put(BigInteger.valueOf(2), BigInteger.ONE);
return;
} else if(index.remainder(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
// index is divisible by 2
// FORMUMA: F(2k) = F(k)[2F(k+1)−F(k)]
// add F(k) key to termsToCalculate (the key is replaced if it is already there, we are working with a map here)
termsToCalculate.put(index.divide(BigInteger.valueOf(2)), null);
populateMapWhitTerms(termsToCalculate, index.divide(BigInteger.valueOf(2)));
// add F(k+1) to termsToCalculate
termsToCalculate.put(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE), null);
populateMapWhitTerms(termsToCalculate, index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE));
} else {
// index is odd
// FORMULA: F(2k+1) = F(k+1)^2+F(k)^2
// add F(k+1) to termsToCalculate
termsToCalculate.put(((index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)).add(BigInteger.ONE)),null);
populateMapWhitTerms(termsToCalculate,((index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)).add(BigInteger.ONE)));
// add F(k) to termsToCalculate
termsToCalculate.put((index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)), null);
populateMapWhitTerms(termsToCalculate, (index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)));
}
}
This method of solution is called dynamic programming
In this method we are remembering the previous results
so when recursion happens then the cpu doesn't have to do any work to recompute the same value again and again
class fibonacci
{
static int fib(int n)
{
/* Declare an array to store Fibonacci numbers. */
int f[] = new int[n+1];
int i;
/* 0th and 1st number of the series are 0 and 1*/
f[0] = 0;
f[1] = 1;
for (i = 2; i <= n; i++)
{
/* Add the previous 2 numbers in the series
and store it */
f[i] = f[i-1] + f[i-2];
}
return f[n];
}
public static void main (String args[])
{
int n = 9;
System.out.println(fib(n));
}
}
public static long getFib(final int index) {
long a=0,b=0,total=0;
for(int i=0;i<= index;i++) {
if(i==0) {
a=0;
total=a+b;
}else if(i==1) {
b=1;
total=a+b;
}
else if(i%2==0) {
total = a+b;
a=total;
}else {
total = a+b;
b=total;
}
}
return total;
}
I have checked all solutions and for me, the quickest one is to use streams and this code could be easily modified to collect all Fibonacci numbers.
public static Long fibonaciN(long n){
return Stream.iterate(new long[]{0, 1}, a -> new long[]{a[1], a[0] + a[1]})
.limit(n)
.map(a->a[0])
.max(Long::compareTo)
.orElseThrow();
}
50 or just below 50 is as far as you can go with straight recursive implementation. You can switch to iterative or dynamic programming (DP) approaches if you want to go much higher than that. I suggest learning about those from this: https://www.javacodegeeks.com/2014/02/dynamic-programming-introduction.html. And don't forget to look the a solution in the comment by David therein, real efficient. The links shows how even n = 500000 can be computed instantaneously using the DP method. The link also explains the concept of "memoization" to speed up computation by storing intermediate (but later on re-callable) results.
I know most people don't like writing methods for people but i was hoping someone could help me convert my algorithm into Java code. I hope my algorithm is good and actually works.
Sort a given array of ints into ascending order. Set Group Limit to 15 (that means that the sum of the group is not greater than 15).
Take the first element of the sorted array and insert into a Group (new array/list) eg. Group A.
Take the second element of the sorted array and insert unless it will make it exceed the group limit. If it exceeds, create a new Group B and insert there.
Take third element and try to insert into next available group.
Repeat until all ints have been checked and grouped.
Input:
egArray = [1,3,4,6,6,9,12,14]
Output:
Group A: [1,3,4,6], Group B: [6,9], Group C: [12], Group D: [14]
I have tried to do this, but failed epically, not even worth me posting my code. :-(
This is an example data and an algorithm I've made up for self learning, so please keep the criticism to a minimum. I genuinely learn from a lot of Stackoverflow posts people have written over the last few months, unfortunately I couldn't find one like this example. Thanks.
Try this:
public static void main(String[] arguments) {
int limit = 15;
int[] egArray = new int[] { 14, 1, 3, 4, 6, 6, 9, 12 };
ArrayList<ArrayList<Integer>> a = grouping(limit, egArray);
System.out.println(a);
}
public static ArrayList<ArrayList<Integer>> grouping(int limit, int[] array) {
// Sort the input array.
Arrays.sort(array);
// Copy the int[] to an ArrayList<Integer>
ArrayList<Integer> input = new ArrayList<>();
for (int i = 0; i < array.length; i++) {
input.add(array[i]);
}
// Initialize the groups
ArrayList<ArrayList<Integer>> groups = new ArrayList<>();
groups.add(new ArrayList<Integer>());
// Initialize the sums of the groups, to increase performance (I guess).
ArrayList<Integer> sums = new ArrayList<>();
sums.add(0);
// Iterate through the input array until there is no number
// left in it (that means we just added all the numbers
// into our groups array).
while (!input.isEmpty()) {
int n = input.get(0); // Store the number to 'n', to shortcut.
if (n > limit) {
String msg = "number is greater than the limit; cannot add number";
throw new IllegalArgumentException(msg);
// Or whatever to do if the number is larger than the limit.
}
boolean match = false;
// Search the next groups and check if our current
// number ('n') fits.
for (int i = 0; i < sums.size(); i++) {
if (sums.get(i) + n <= limit) {
// If it fits, then add the number to the group.
sums.set(i, sums.get(i) + n);
groups.get(i).add(n);
match = true;
break;
}
}
// If 'n' doesn't fit in any group, create a new one.
if (!match) {
ArrayList<Integer> e = new ArrayList<>();
e.add(n);
groups.add(e);
sums.add(n);
}
// Remove our number.
input.remove(0);
}
return groups;
}
Notice that the method returns an ArrayList<ArrayList<Integer>> instead of an int[][], but the effect is the same. In order to check the values of the groups, just run the main(String).
How about this method?
public static ArrayList group(ArrayList<Integer> arr, Integer groupLimit) {
ArrayList<ArrayList> result = new ArrayList<ArrayList>();
ArrayList<Integer> temp = new ArrayList<Integer>();
for (Integer x : arr) {
if (sumElements(temp) + x < groupLimit) {
temp.add(x);
} else {
result.add(temp);
temp = new ArrayList<Integer>();
temp.add(x);
}
}
if (temp.size() > 0) {
result.add(temp);
}
return result;
}
public static int sumElements(ArrayList<Integer> arr) {
Integer result = 0;
for(Integer x:arr) result += x;
return result;
}