I'm playing with Java 8 Spliterator and created one to stream Fibonacci numbers up to a given n. So for the Fibonacci series 0, 1, 1, 2, 3, 5, 8, ...
n fib(n)
-----------
-1 0
1 0
2 1
3 1
4 2
Following is my implementation which prints a bunch of 1 before running out of stack memory. Can you help me find the bug? (I think it's not advancing the currentIndex but I'm not sure what value to set it to).
Edit 1: If you decide to answer, please keep it relevant to the question. This question is not about efficient fibonacci number generation; it's about learning spliterators.
FibonacciSpliterator:
#RequiredArgsConstructor
public class FibonacciSpliterator implements Spliterator<FibonacciPair> {
private int currentIndex = 3;
private FibonacciPair pair = new FibonacciPair(0, 1);
private final int n;
#Override
public boolean tryAdvance(Consumer<? super FibonacciPair> action) {
// System.out.println("tryAdvance called.");
// System.out.printf("tryAdvance: currentIndex = %d, n = %d, pair = %s.\n", currentIndex, n, pair);
action.accept(pair);
return n - currentIndex >= 2;
}
#Override
public Spliterator<FibonacciPair> trySplit() {
// System.out.println("trySplit called.");
FibonacciSpliterator fibonacciSpliterator = null;
if (n - currentIndex >= 2) {
// System.out.printf("trySplit Begin: currentIndex = %d, n = %d, pair = %s.\n", currentIndex, n, pair);
fibonacciSpliterator = new FibonacciSpliterator(n);
long currentFib = pair.getMinusTwo() + pair.getMinusOne();
long nextFib = pair.getMinusOne() + currentFib;
fibonacciSpliterator.pair = new FibonacciPair(currentFib, nextFib);
fibonacciSpliterator.currentIndex = currentIndex + 3;
// System.out.printf("trySplit End: currentIndex = %d, n = %d, pair = %s.\n", currentIndex, n, pair);
}
return fibonacciSpliterator;
}
#Override
public long estimateSize() {
return n - currentIndex;
}
#Override
public int characteristics() {
return ORDERED | IMMUTABLE | NONNULL;
}
}
FibonacciPair:
#RequiredArgsConstructor
#Value
public class FibonacciPair {
private final long minusOne;
private final long minusTwo;
#Override
public String toString() {
return String.format("%d %d ", minusOne, minusTwo);
}
}
Usage:
Spliterator<FibonacciPair> spliterator = new FibonacciSpliterator(5);
StreamSupport.stream(spliterator, true)
.forEachOrdered(System.out::print);
Besides the fact that your code is incomplete, there are at least two errors in your tryAdvance method recognizable. First, you are not actually making any advance. You are not modifying any state of your spliterator. Second, you are unconditionally invoking the action’s accept method which is not matching the fact that you are returning a conditional value rather than true.
The purpose of tryAdvance is:
as the name suggests, try to make an advance, i.e. calculate a next value
if there is a next value, invoke action.accept with that value and return true
otherwise just return false
Note further that your trySplit() does not look very convincing, I don’t even know where to start. You are better off, inheriting from AbstractSpliterator and not implementing a custom trySplit(). Your operation doesn’t benefit from parallel execution anyway. A stream constructed with that source could only gain an advantage from parallel execution if you chain it with quiet expensive per-element operations.
In general you don't need implementing the spliterator. If you really need a Spliterator object, you may use stream for this purpose:
Spliterator.OfLong spliterator = Stream
.iterate(new long[] { 0, 1 },
prev -> new long[] { prev[1], prev[0] + prev[1] })
.mapToLong(pair -> pair[1]).spliterator();
Testing:
for(int i=0; i<20; i++)
spliterator.tryAdvance((LongConsumer)System.out::println);
Please note that holding Fibonacci numbers in long variable is questionable: it overflows after Fibonacci number 92. So if you want to create spliterator which just iterates over first 92 Fibonacci numbers, I'd suggest to use predefined array for this purpose:
Spliterator.OfLong spliterator = Spliterators.spliterator(new long[] {
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765,
10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309,
3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141,
267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073L, 4807526976L,
7778742049L, 12586269025L, 20365011074L, 32951280099L, 53316291173L, 86267571272L, 139583862445L,
225851433717L, 365435296162L, 591286729879L, 956722026041L, 1548008755920L, 2504730781961L,
4052739537881L, 6557470319842L, 10610209857723L, 17167680177565L, 27777890035288L,
44945570212853L, 72723460248141L, 117669030460994L, 190392490709135L, 308061521170129L,
498454011879264L, 806515533049393L, 1304969544928657L, 2111485077978050L, 3416454622906707L,
5527939700884757L, 8944394323791464L, 14472334024676221L, 23416728348467685L, 37889062373143906L,
61305790721611591L, 99194853094755497L, 160500643816367088L, 259695496911122585L, 420196140727489673L,
679891637638612258L, 1100087778366101931L, 1779979416004714189L, 2880067194370816120L,
4660046610375530309L, 7540113804746346429L
}, Spliterator.ORDERED);
Array spliterator also splits well, so you will have real parallel processing.
Ok, let's write the spliterator. Using OfLong is still too boring: let's switch to BigInteger and don't limit user by 92. The tricky thing here is to quickly jump to the given Fibonacci number. I'll use matrix multiplication algorithm described here for this purpose. Here's my code:
static class FiboSpliterator implements Spliterator<BigInteger> {
private final static BigInteger[] STARTING_MATRIX = {
BigInteger.ONE, BigInteger.ONE,
BigInteger.ONE, BigInteger.ZERO};
private BigInteger[] state; // previous and current numbers
private int cur; // position
private final int fence; // max number to cover by this spliterator
public FiboSpliterator(int max) {
this(0, max);
}
// State is not initialized until traversal
private FiboSpliterator(int cur, int fence) {
assert fence >= 0;
this.cur = cur;
this.fence = fence;
}
// Multiplication of 2x2 matrix, by definition
static BigInteger[] multiply(BigInteger[] m1, BigInteger[] m2) {
return new BigInteger[] {
m1[0].multiply(m2[0]).add(m1[1].multiply(m2[2])),
m1[0].multiply(m2[1]).add(m1[1].multiply(m2[3])),
m1[2].multiply(m2[0]).add(m1[3].multiply(m2[2])),
m1[2].multiply(m2[1]).add(m1[3].multiply(m2[3]))};
}
// Log(n) algorithm to raise 2x2 matrix to n-th power
static BigInteger[] power(BigInteger[] m, int n) {
assert n > 0;
if(n == 1) {
return m;
}
if(n % 2 == 0) {
BigInteger[] root = power(m, n/2);
return multiply(root, root);
} else {
return multiply(power(m, n-1), m);
}
}
#Override
public boolean tryAdvance(Consumer<? super BigInteger> action) {
if(cur == fence)
return false; // traversal finished
if(state == null) {
// initialize state: done only once
if(cur == 0) {
state = new BigInteger[] {BigInteger.ZERO, BigInteger.ONE};
} else {
BigInteger[] res = power(STARTING_MATRIX, cur);
state = new BigInteger[] {res[1], res[0]};
}
}
action.accept(state[1]);
// update state
if(++cur < fence) {
BigInteger next = state[0].add(state[1]);
state[0] = state[1];
state[1] = next;
}
return true;
}
#Override
public Spliterator<BigInteger> trySplit() {
if(fence - cur < 2)
return null;
int mid = (fence+cur) >>> 1;
if(mid - cur < 100) {
// resulting interval is too small:
// instead of jumping we just store prefix into array
// and return ArraySpliterator
BigInteger[] array = new BigInteger[mid-cur];
for(int i=0; i<array.length; i++) {
tryAdvance(f -> {});
array[i] = state[0];
}
return Spliterators.spliterator(array, ORDERED | NONNULL | SORTED);
}
// Jump to another position
return new FiboSpliterator(cur, cur = mid);
}
#Override
public long estimateSize() {
return fence - cur;
}
#Override
public int characteristics() {
return ORDERED | IMMUTABLE | SIZED| SUBSIZED | NONNULL | SORTED;
}
#Override
public Comparator<? super BigInteger> getComparator() {
return null; // natural order
}
}
This implementation actually faster in parallel for very big fence value (like 100000). Probably even wiser implementation is also possible which would split unevenly reusing the intermediate results of matrix multiplication.
Related
I'm trying to implement a backtracking algorithm to balance weights on a scale. It's for university, so there are given weights I have to use (0, 2, 7, 20, 70, 200, 700). Weights can be placed on the scale multiple times to match the input. For example: input(80) -> result(20, 20, 20, 20) or input(16) -> result(7,7,2).
I have to use backtracking and recursion.
I have difficulties understanding how to do the backtracking if a proposal is wrong. I can only step back one step, but if the right solution requires two steps back my algorithm fails.
So my method isInvalid() is checking if the sum of all counterweights is higher than the input. If so, it will remove the last weight.
I guess this is my problem. For input(16) it produces (7,7,2) --> correct.
But for input(21) it never finishes, because it tries to add 20, and then tries to add 7. Then it will be over 21 and will remove 7, but it will never remove the 20.
/* This is my backtracking algorithm */
public Proposal calc(Proposal proposal) {
Proposal result;
if(proposal.isInvalid()) return null;
if(proposal.isSolution()) return proposal;
for (int i : proposal.possibleNextSteps()) {
Proposal newProposal = new Proposal(proposal.getWeight(), proposal.getCounterWeights());
newProposal.apply(i);
result = calc(newProposal);
if (result != null) return result;
}
return null;
}
/* this is the class Proposal (only required parts) */
public class Proposal {
private int weight;
private ArrayList<Integer> counterWeights;
private static Integer[] weights = {0, 2, 7, 20, 70, 200};
public Proposal(int weight, ArrayList<Integer> counterWeights) {
this.weight = weight;
this.counterWeights = counterWeights;
Arrays.sort(weights, Collections.reverseOrder());
}
public boolean isInvalid() {
if(counterWeights.stream().mapToInt(i -> i.intValue()).sum() > weight) {
counterWeights.remove(counterWeights.size()-1);
return true;
}
return false;
}
public boolean isSolution() {
return counterWeights.stream().mapToInt(value -> value).sum() == weight;
}
public Integer[] possibleNextSteps() {
return weights;
}
public void apply(int option) {
this.counterWeights.add(option);
}
}
What am I doing wrong?
And also, is this the right way to reverse my array of weights?
Thanks!
EDIT:
I tried something different.
I changed this:
Proposal newProposal = new Proposal(proposal.getWeight()- proposal.getSum(), new ArrayList<>());
And this:
public boolean isInvalid() {
return counterWeights.stream().mapToInt(value -> value).sum() > weight;
}
So now if I follow it step by step in debug mode, it is pretty much doing what I want it to do, but it does not pass the solutions from my recursion to my previous solution, so they do not add up to a final solution.
So basically I break down the problem in smaller problems (once i find a weight that fits, I'll call the method recursively with the difference between the total weight and the solution I've already found). But how do I pass the solutions to the calling method?
In the following implementation, a solution is an array of coefficients. a coefficient at index i is the number of times the weight at position i appears in the solution.
Note that you can have several solutions giving the same total weight, this implementation gives them all. It's easy to change it to return only the first solution found.
The recursive methode void solve(int weight, int n, int total) tries for index n all integers for which the total weight is no greater than the target weight.
public class Solver {
private final int[] weights;
private int[] current;
private final List<int[]> solutions = new ArrayList<>();
public Solver(int...weights) {
this.weights = weights;
}
public int[][] solve(int weight) {
current = new int[weights.length];
solutions.clear();
solve(weight, 0, 0);
return solutions.toArray(new int[solutions.size()][]);
}
public void printSolution(int[] solution) {
int total = 0;
for (int i = 0; i < solution.length; ++i) {
for (int j = 0; j < solution[i]; ++j) {
System.out.print(weights[i] + " ");
total += weights[i];
}
}
System.out.println(" total: " + total);
System.out.println();
}
private void solve(int weight, int n, int total) {
if (n >= current.length) {
if (total == weight) {
solutions.add(current.clone());
}
} else {
solve(weight, n+1, total);
while (total < weight) {
++current[n];
total += weights[n];
solve(weight, n+1, total);
}
current[n] = 0;
}
}
}
How to break stream computation based on previous results? If it's obvious that stream.filter(...).count() would be less than some number - how to stop stream computation?
I have the following code which checks if some sampleData passes the predicate test:
// sampleData.size() may be greater than 10.000.000
Set<String> sampleData = downloadFromWeb();
return sampleData.stream().filter(predicate::test).count() > sampleData.size() * coefficient;
I could have thousands of sampleData. The problem is that this code is ineffective. For example, if coefficient equals 0.5, sampleData.size() = 10_000_000, and first 5_000_000 elements fails the predicate::test - there is no reason to validate last 5_000_000 elements (count() will never be greater than 5_000_000).
ZhekaKozlov’s answer is heading into the right direction, but it lacks the negation. For the matches to be larger than a certain threshold, the number of non matching elements must be smaller than “size - threshold”. If we test for the nonmatching elements to be smaller, we can apply a limit to stop once they become larger:
Set<String> sampleData = downloadFromWeb();
final long threshold = sampleData.size()-(long)(sampleData.size() * coefficient);
return sampleData.stream()
.filter(predicate.negate()).limit(threshold+1).count() < threshold;
There is, by the way, no reason to create a method reference to the test method of an existing Predicate like with predicate::test. Just pass the Predicate to the filter method. The code above also uses predicate.negate() instead of predicate.negate()::test…
To be honest I am not quite sure this would be correct, I hope someone will come along and review this, but here is my idea of using a custom spliterator:
static class CustomSpl<T> extends AbstractSpliterator<T> {
private Spliterator<T> source;
private int howMany;
private int coefficient;
private Predicate<T> predicate;
private T current;
private long initialSize;
private void setT(T t) {
this.current = t;
}
public CustomSpl(Spliterator<T> source, int howMany, int coefficient, Predicate<T> predicate, long initialSize) {
super(source.estimateSize(), source.characteristics());
this.source = source;
this.howMany = howMany;
this.coefficient = coefficient;
this.predicate = predicate;
this.initialSize = initialSize;
}
#Override
public boolean tryAdvance(Consumer<? super T> action) {
boolean hasMore = source.tryAdvance(this::setT);
System.out.println(current);
if (!hasMore) {
return false;
}
if (predicate.test(current)) {
++howMany;
}
if (initialSize - howMany <= coefficient) {
return false;
}
action.accept(current);
return true;
}
}
And for example this will produce only 4 elements, since we said to only care having a coefficient 5:
Spliterator<Integer> sp = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).stream().spliterator();
long count = StreamSupport.stream(new CustomSpl<>(sp, 0, 5, x -> x > 3, sp.getExactSizeIfKnown()), false)
.count();
Also this is possible for spliterators with known size only.
Set<String> sampleData = downloadFromWeb();
int size = (int) (sampleData.size() * coefficient);
return sampleData.stream().filter(predicate::test).limit(size + 1).count() > size;
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 need to keep top N(< 1000) integers while trying to add values from a big list of integers(around a million sized lazy list). I want to be try adding values to a collection but that needs to keep only the top N(highest values) integers. Is there any preferred data structure to use for this purpose ?
I'd suggest to use some sorted data structure, such as TreeSet. Before insertion, check the number of items in the set, and if it reached 1000, remove the smallest number if it's smaller than the newly added number, and add the new number.
TreeSet<Integer> set = ...;
public void add (int n) {
if (set.size () < 1000) {
set.add (n);
} else {
Integer first = set.first();
if (first.intValue() < n) {
set.pollFirst();
set.add (n);
}
}
}
Google Guava MinMaxPriorityQueue class.
You can also use custom sorting by using a comparator (Use orderedBy(Comparator<B> comparator) method).
Note: This collection is NOT a sorted collection.
See javadoc
Example:
#Test
public void test() {
final int maxSize = 5;
// Natural order
final MinMaxPriorityQueue<Integer> queue = MinMaxPriorityQueue
.maximumSize(maxSize).create();
queue.addAll(Arrays.asList(10, 30, 60, 70, 20, 80, 90, 50, 100, 40));
assertEquals(maxSize, queue.size());
assertEquals(new Integer(50), Collections.max(queue));
System.out.println(queue);
}
Output:
[10, 50, 40, 30, 20]
One efficient solution is a slightly tweaked array-based priority queue using a binary min-heap.
First N integers are simply added to the heap one by one or you can build it from array of first N integers (slightly faster).
After that, compare the incoming integer with the root element (which is MIN value found so far). If the new integer is larger that that, simply replace the root with this new integer and perform down-heap operation (i.e. trickle down the new integer until both its children are smaller or it becomes a leaf). The data structure guarantees you will always have N largest integers so far with average addition time of O(log N).
Here is my C# implementation, the mentioned method is named "EnqueueDown". The "EnqueueUp" is a standard enqueue operation that expands the array, adds new leaf and trickles it up.
I have tested it on 1M numbers with max heap size of 1000 and it runs under 200 ms:
namespace ImagingShop.Research.FastPriorityQueue
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
public sealed class FastPriorityQueue<T> : IEnumerable<Tuple<T, float>>
{
private readonly int capacity;
private readonly Tuple<T, float>[] nodes;
private int count = 0;
public FastPriorityQueue(int capacity)
{
this.capacity = capacity;
this.nodes = new Tuple<T, float>[capacity];
}
public int Capacity => this.capacity;
public int Count => this.count;
public T FirstNode => this.nodes[0].Item1;
public float FirstPriority => this.nodes[0].Item2;
public void Clear()
{
this.count = 0;
}
public bool Contains(T node) => this.nodes.Any(tuple => Equals(tuple.Item1, node));
public T Dequeue()
{
T nodeHead = this.nodes[0].Item1;
int index = (this.count - 1);
this.nodes[0] = this.nodes[index];
this.count--;
DownHeap(index);
return nodeHead;
}
public void EnqueueDown(T node, float priority)
{
if (this.count == this.capacity)
{
if (priority < this.nodes[0].Item2)
{
return;
}
this.nodes[0] = Tuple.Create(node, priority);
DownHeap(0);
return;
}
int index = this.count;
this.count++;
this.nodes[index] = Tuple.Create(node, priority);
UpHeap(index);
}
public void EnqueueUp(T node, float priority)
{
int index = this.count;
this.count++;
this.nodes[index] = Tuple.Create(node, priority);
UpHeap(index);
}
public IEnumerator<Tuple<T, float>> GetEnumerator()
{
for (int i = 0; i < this.count; i++) yield return this.nodes[i];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DownHeap(int index)
{
while (true)
{
int indexLeft = (index << 1);
int indexRight = (indexLeft | 1);
int indexMin = ((indexLeft < this.count) && (this.nodes[indexLeft].Item2 < this.nodes[index].Item2))
? indexLeft
: index;
if ((indexRight < this.count) && (this.nodes[indexRight].Item2 < this.nodes[indexMin].Item2))
{
indexMin = indexRight;
}
if (indexMin == index)
{
break;
}
Flip(index, indexMin);
index = indexMin;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Flip(int indexA, int indexB)
{
var temp = this.nodes[indexA];
this.nodes[indexA] = this.nodes[indexB];
this.nodes[indexB] = temp;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UpHeap(int index)
{
while (true)
{
if (index == 0)
{
break;
}
int indexParent = (index >> 1);
if (this.nodes[indexParent].Item2 <= this.nodes[index].Item2)
{
break;
}
Flip(index, indexParent);
index = indexParent;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
The basic implementation is taken from "Cormen, Thomas H. Introduction to algorithms. MIT press, 2009."
In Java 1.7 one may use java.util.PriorityQueue. To keep the top N items you need to use reverse comparator, e.g. for integers you order them descending. In this manner the smallest number is always on top and could be removed if to many items in queue.
package eu.pawelsz.example.topn;
import java.util.Comparator;
import java.util.PriorityQueue;
public class TopN {
public static <E> void add(int keep, PriorityQueue<E> priorityQueue, E element) {
if (keep == priorityQueue.size()) {
priorityQueue.poll();
}
priorityQueue.add(element);
}
public static void main(String[] args) {
int N = 4;
PriorityQueue<Integer> topN = new PriorityQueue<>(N, new Comparator<Integer>() {
#Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
add(N, topN, 1);
add(N, topN, 2);
add(N, topN, 3);
add(N, topN, 4);
System.out.println("smallest: " + topN.peek());
add(N, topN, 8);
System.out.println("smallest: " + topN.peek());
add(N, topN, 5);
System.out.println("smallest: " + topN.peek());
add(N, topN, 2);
System.out.println("smallest: " + topN.peek());
}
}
// this Keep Top Most K Instance in Queue
public static <E> void add(int keep, PriorityQueue<E> priorityQueue, E element) {
if(priorityQueue.size()<keep){
priorityQueue.add(element);
}
else if(keep == priorityQueue.size()) {
priorityQueue.add(element); // size = keep +1 but
Object o = (Object)topN.toArray()[k-1];
topN.remove(o); // resized to keep
}
}
The fastest way is likely a simple array items = new Item[N]; and a revolving cursor int cursor = 0;. The cursor points to the insertion point of the next element.
To add a new element use the method
put(Item newItem) { items[cursor++] = newItem; if(cursor == N) cursor = 0; }
when accessing this structure you can make the last item added appear at index 0 via a small recalculation of the index, i.e.
get(int index) { return items[ cursor > index ? cursor-index-1 : cursor-index-1+N ]; }
(the -1 is because cursor always point at the next insertion point, i.e. cursor-1 is the last element added).
Summary: put(item) will add a new item. get(0) will get the last item added, get(1) will get the second last item, etc.
In case you need to take care of the case where n < N elements have been added you just need to check for null.
(TreeSets will likely be slower)
Your Question is answered here:
Size-limited queue that holds last N elements in Java
To summerize it:
No there is no data structure in the default java sdk, but Apache commons collections 4 has a CircularFifoQueue.
I know my code has a lot of issues right now, but I just want to get the ideas correct before trying anything. I need to have a method which accepts an integer n that returns the nth number in the Fibonacci sequence. While solving it normally with recursion, I have to minimize runtime so when it gets something like the 45th integer, it will still run fairly quickly. Also, I can't use class constants and globals.
The normal way w/ recursion.
public static int fibonacci(int n) {
if (n <= 2) { // to indicate the first two elems in the sequence
return 1;
} else { // goes back to very first integer to calculate (n-1) and (n+1) for (n)
return fibonacci(n-1) + fibonacci(n-2);
}
}
I believe the issue is that there is a lot of redundancy in this process. I figure that I can create a List to calculate up to nth elements so it only run through once before i return the nth element. However, I am having trouble seeing how to use recursion in that case though.
If I am understanding it correctly, the standard recursive method is slow because there are a lot of repeats:
fib(6) = fib(5) + fib(4)
fib(5) = fib(4) + fib(3)
fib(4) = fib(3) + 1
fib(3) = 1 + 1
Is this the correct way of approaching this? Is it needed to have some form of container to have a faster output while still being recursive? Should I use a helper method? I just recently got into recursive programming and I am having a hard time wrapping my head around this since I've been so used to iterative approaches. Thanks.
Here's my flawed and unfinished code:
public static int fasterFib(int n) {
ArrayList<Integer> results = new ArrayList<Integer>();
if (n <= 2) { // if
return 1;
} else if (results.size() <= n){ // If the list has fewer elems than
results.add(0, 1);
results.add(0, 1);
results.add(results.get(results.size() - 1 + results.get(results.size() - 2)));
return fasterFib(n); // not sure what to do with this yet
} else if (results.size() == n) { // base case if reached elems
return results.get(n);
}
return 0;
}
I think you want to use a Map<Integer, Integer> instead of a List. You should probably move that collection outside of your method (so it can cache the results) -
private static Map<Integer, Integer> results = new HashMap<>();
public static int fasterFib(int n) {
if (n == 0) {
return 0;
} else if (n <= 2) { // if
return 1;
}
if (results.get(n) != null) {
return results.get(n);
} else {
int v = fasterFib(n - 1) + fasterFib(n - 2);
results.put(n, v);
return v;
}
}
This optimization is called memoization, from the Wikipedia article -
In computing, memoization is an optimization technique used primarily to speed up computer programs by keeping the results of expensive function calls and returning the cached result when the same inputs occur again.
You can use Map::computeIfAbsent method (since 1.8) to re-use the already calculated numbers.
import java.util.HashMap;
import java.util.Map;
public class Fibonacci {
private final Map<Integer, Integer> cache = new HashMap<>();
public int fib(int n) {
if (n <= 2) {
return n;
} else {
return cache.computeIfAbsent(n, (key) -> fib(n - 1) + fib(n - 2));
}
}
}
The other way to do this is to use a helper method.
static private int fibonacci(int a, int b, int n) {
if(n == 0) return a;
else return fibonacci(b, a+b, n-1);
}
static public int fibonacci(int n) {
return fibonacci(0, 1, n);
}
How about a class and a private static HashMap?
import java.util.HashMap;
public class Fibonacci {
private static HashMap<Integer,Long> cache = new HashMap<Integer,Long>();
public Long get(Integer n) {
if ( n <= 2 ) {
return 1L;
} else if (cache.containsKey(n)) {
return cache.get(n);
} else {
Long result = get(n-1) + get(n-2);
cache.put(n, result);
System.err.println("Calculate once for " + n);
return result;
}
}
/**
* #param args
*/
public static void main(String[] args) {
Fibonacci f = new Fibonacci();
System.out.println(f.get(10));
System.out.println(f.get(15));
}
}
public class Fibonacci {
private Map<Integer, Integer> cache = new HashMap<>();
private void addToCache(int index, int value) {
cache.put(index, value);
}
private int getFromCache(int index) {
return cache.computeIfAbsent(index, this::fibonacci);
}
public int fibonacci(int i) {
if (i == 1)
addToCache(i, 0);
else if (i == 2)
addToCache(i, 1);
else
addToCache(i, getFromCache(i - 1) + getFromCache(i - 2));
return getFromCache(i);
}
}
You can use memoization (store the values you already have in an array, if the value at a given index of this array is not a specific value you have given to ignore --> return that).
Code:
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n = Integer.parseInt(s.nextLine());
int[] memo = new int[n+1];
for (int i = 0; i < n+1 ; i++) {
memo[i] = -1;
}
System.out.println(fib(n,memo));
}
static int fib(int n, int[] memo){
if (n<=1){
return n;
}
if(memo[n] != -1){
return memo[n];
}
memo[n] = fib(n-1,memo) + fib(n-2,memo);
return memo[n];
}
Explaination:
memo :
-> int array (all values -1)
-> length (n+1) // easier for working on index
You assign a value to a given index of memo ex: memo[2]
memo will look like [-1,-1, 1, ..... ]
Every time you need to know the fib of 2 it will return memo[2] -> 1
Which saves a lot of computing time on bigger numbers.
private static Map<Integer, Integer> cache = new HashMap<Integer, Integer(){
{
put(0, 1);
put(1, 1);
}
};
/**
* Smallest fibonacci sequence program using dynamic programming.
* #param n
* #return
*/
public static int fibonacci(int n){
return n < 2 ? n : cache.computeIfAbsent(n, (key) -> fibonacci( n - 1) + fibonacci(n - 2));
}
public static long Fib(int n, Dictionary<int, long> dict)
{
if (n <= 1)
return n;
if (dict.ContainsKey(n))
return dict[n];
var value = Fib(n - 1,dict) + Fib(n - 2,dict);
dict[n] = value;
return value;
}