Related
My task is to write a program to calculate shortest time it takes to go from node A(start) to node B(end) on a weighted graph(I'm using dijkstra algorithm).
Time requirement is 2 seconds on memory limit is 64 MB and I can assume that entered data is valid
First line has 4 whole numbers:
Amount of nodes M(2 ≤ M ≤ 20000)
Amount of edges(connections) N(0 ≤ N ≤ 50000)
Start node A(0 ≤ A < M) and end node O (0 ≤ O < M).
Next N lines has connection info represented with three whole numbers:
connected computers and the time between them in milliseconds(edge weight).
My code doesn't pass all the tests. If i test my code with a big graph then it fails as heap memory runs out(about 900MB on my machine).
My problem: How do i optimize my code so it fits into requirements?
Would using adjacency list be enough?
My code is this:
import java.util.ArrayList;
import java.util.Scanner;
public class Route3 {
public static int minDistance(ArrayList<Long> mindist, ArrayList<Boolean> visited){
long min = Long.MAX_VALUE;
int minindex = -1;
for (int i = 0; i < mindist.size(); i++) {
if(!visited.get(i) && (mindist.get(i) <= min)) {
min = mindist.get(i);
minindex = i;
}
}
return minindex;
}
public static long dijkstra(long[][] graph, int start, int end) {
int computers = graph.length;
ArrayList<Boolean> traversed = new ArrayList<>(); //Hold traversed nodes
for (int i = 0; i < computers; i++) {
traversed.add(i,false);
}
ArrayList<Long> mindist = new ArrayList<>(); //Holds mindistances to nodes based on index
for (int i = 0; i < computers; i++) {
mindist.add(i,Long.MAX_VALUE);
}
mindist.set(start,(long)0);
for (int i = 0; i < computers; i++) {
int min = minDistance(mindist,traversed);
if(min == -1) return mindist.get(end);
traversed.set(min,true);
if(min == end) return mindist.get(min) == Long.MAX_VALUE ? -1 : mindist.get(min); //Error check
for (int j = 0; j < computers; j++) {
if(!traversed.get(j) && graph[min][j] != 0 && mindist.get(min) + graph[min][j] < mindist.get(j)) {
mindist.set(j,(mindist.get(min) + graph[min][j]));
}
}
}
return mindist.get(end) == Long.MAX_VALUE ? -1 : mindist.get(end);
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int computers = in.nextInt(); //nodes
int connections = in.nextInt(); //edges
int start = in.nextInt();
int end = in.nextInt();
long[][] graph = new long[computers+1][computers+1];
for (int i = 0; i < connections; i++) {
int x = in.nextInt();
int y = in.nextInt();
long t = in.nextLong();
graph[x][y] = t;
graph[y][x] = t;
}
if(connections == 0) {
System.out.println(-1);
System.exit(0);
}
long dist = dijkstra(graph,start,end);
if(dist != -1) System.out.println(dist);
else System.out.println(-1);
}
}
All help is appreciated!
I think that you'll have to find a better way to hold the graph information. This line:
long[][] graph = new long[computers+1][computers+1]
could take up to 20001*20001*8 bytes, that is 3GB!
As your net has few connections per node I'd suggest storing the graph as a HashMap of HashMaps of connections:
class Connection {
int nodeA, nodeB;
long time;
}
HashMap<Integer, HashMap<Integer, Connection>> graph;
It may sound less efficient, but you are saving all the blank edges. Then you add the Connection to the graph indexed by both nodes (nodeA and nodeB):
void addConnection(Connection c)
{
HashMap<Integer, Connection> subgraph = graph.get(c.nodeA);
if(subgraph == null)
subgraph = new HashMap<>();
subgraph.put(c.nodeB, c);
HashMap<Integer, Connection> subgraph = graph.get(c.nodeB);
if(subgraph == null)
subgraph = new HashMap<>();
subgraph.put(c.nodeA, c);
}
And retrieve the connection descriptor like:
long getConnection(int nodeA, int nodeB)
{
ArrayList<Connection> subgraph = graph.get(nodeA);
if(subgraph == null)
return 0L;
Connection c = subgraph.get(nodeB);
if(c == null)
return 0L;
return c.time;
}
This should make your program slower but much more memory efficient.
WARNING: The code is not tested, it's just for clarification.
I have a program that generates an array based on the user input (the array can be descending, ascending and two types of random) and then it calculates the maximum subarray sum using bruteforce, divide and conquer, and dynamic programming. It seems to work fine and dandy up to values of 65535. After that, each sum is different, which shouldn't happen. 35535 is 2 to the power of 16 minus 1, so I was wondering if I'm hitting some limit. When I print the array it seems to print fine, so I don't think that the problem is that the array isn't generating properly.
This is the main class:
public class MainClass {
public static void main(String[] args) {
int n = Integer.parseInt(args[1]);
int[] maxsubarray1;
maxsubarray1 = new Generator(n,args[3]).getArray();
int[] maxsubarray2 = Arrays.copyOf(maxsubarray1,maxsubarray1.length);
int[] maxsubarray3 = Arrays.copyOf(maxsubarray1,maxsubarray1.length);
System.out.println(Arrays.toString(maxsubarray1));
solver solver = new solver();
int solution;
//if (args[5].equalsIgnoreCase("bruteforce")){
long startTime = System.currentTimeMillis();
solution = solver.bruteforce(maxsubarray1, n);
System.out.println("__________BRUTE FORCE________\nThe sum of the array is "+solution);
long endTime = System.currentTimeMillis() - startTime;
System.out.println(endTime);
//}
//if (args[5].equalsIgnoreCase("divideconquer")){
long startTime2 = System.currentTimeMillis();
int solutiondivideconquer = solver.divideconquer(maxsubarray2, 0, n);
System.out.println("__________DIVIDE AND CONQUERE________\nThe sum of the array is "+ solutiondivideconquer);
long endTime2 = System.currentTimeMillis() - startTime2;
System.out.println(endTime2);
//}
//if (args[5].equalsIgnoreCase("dynprog")){
long startTime3 = System.currentTimeMillis();
int solutiondynprog = solver.dynprog(maxsubarray3, n);
System.out.println("__________DYNAMIC PROGRAMMING________\nThe sum of the array is "+ solutiondynprog);
long endTime3 = System.currentTimeMillis() - startTime3;
System.out.println(endTime3);
//}
}
}
This is the generator code:
import java.util.concurrent.ThreadLocalRandom;
public class Generator {
int size;
String type;
int[] generatedArray;
public Generator(int mysize, String mytype){
size = mysize;
type = mytype;
generatedArray = new int[size];
}
public void ascending(){
for(int i = 0; i < this.size; i++)
generatedArray[i] = i+1;
}
public void descending(){
for(int i = this.size -1; i >= 0; i--)
generatedArray[i] = i+1;
}
public void random(){
for(int i = 0; i <= this.size -1; i++)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10*this.size, 10*this.size);
}
public void randominter(){
for(int i = 0; i <= this.size -1; i++)
if (i % 2 == 0)
generatedArray[i] = ThreadLocalRandom.current().nextInt(1, 10*this.size);
else if (i % 2 == 1)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10*this.size, -1);
}
public int[] getArray(){
if (type.equalsIgnoreCase("descending")){
this.descending();
return generatedArray;
}
if (type.equalsIgnoreCase("ascending")){
this.ascending();
return generatedArray;
}
if (type.equalsIgnoreCase("random")){
this.random();
return generatedArray;
}
if (type.equalsIgnoreCase("randominter")){
this.randominter();
return generatedArray;
}
return null;
}
}
And this is the solver class:
public class solver {
//brute force algorithm with complexity O(n^2)
int bruteforce(int array[], int n){
int max = Integer.MIN_VALUE;
//We go throght all the elements of the list and we try all the
//posible combinations with all the other elements
for (int i = 0; i < n; i++){
int sum = 0;
for (int j = i; j < n ; j++){
//we add the an element in the sum
sum += array[j];
//we check if the sum with the new element is greater that the value we had before
if(sum > max){
//if it's greater, it becomes the new value
max = sum;
}
}
}
//we return the maximum value we have found
return max;
}
//to implement the divide and conquer algorithm we have to take into account the
// maximum subarray can have elements in the right subarray and in the left subarray
int maxCrossingSum(int array[], int l, int m, int h){
int sum = 0;
int left_sum = Integer.MIN_VALUE;
//Has the elements on the left part of the arrray
for ( int i = (int)m; i >= l; i--){
sum = sum + array[i];
if( sum > left_sum ){
left_sum = sum;
}
}
sum = 0;
int right_sum = 0;
//Has the elements in the right part of the array
for ( int j = (int)m+1; j <= h; j++){
sum = sum + array [j];
if (sum > right_sum){
right_sum = sum;
}
}
//returns the sun of the elements on the left and the right of the array
return left_sum + right_sum;
}
//returns the sum of the maximum subarray
int maxSubarraySum(int array[], int l, int h){
if(l == h)
return array[1];
int m = (l + h)/2;
//checks which is the maximum between left and right
int maxBetweenLeftRight = max(maxSubarraySum(array, l, m), maxSubarraySum(array, m+1,h));
int crossing = maxCrossingSum(array, l, m,h-1);
//retrns the maximum between one of the sides and the crossing sum
return max(maxBetweenLeftRight, crossing);
}
//divide and conquere algorithm with complexity O(nlogn)
//only made to make it more understandable from the main
//can call maxSubarraySum and it would be the same
int divideconquer (int array[], int l, int h){
return maxSubarraySum(array, l, h);
}
//dynamic programming algorithm with complexity O(n)
int dynprog(int array[], int n){
int a = array[0];
int b = array[0];
//for all the elements checks if the sum was better until the
//step before or adding the element
for (int i = 1 ; i < n; i++){
a= max (a+ array[i], array[i]);
b= max(b, a);
}
return b;
}
}
Changing all the ints to longs didn't help either.
I've copied your code, changed all ints to longs and it's working fine. Also changed n = Integer.parseInt(args[0]) instead of n = Integer.parseInt(args[1]).
Then I called my program like program_name 1000 random.
I've checked in excel, and only bruteforce was wrong. I've changed Integer.MIN_VALUE to Long.MIN_VALUE. And int sum to long sum.
Main.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class Main {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
long[] maxsubarray1;
maxsubarray1 = new Generator(n, args[1]).getArray();
long[] maxsubarray2 = Arrays.copyOf(maxsubarray1, maxsubarray1.length);
long[] maxsubarray3 = Arrays.copyOf(maxsubarray1, maxsubarray1.length);
System.out.println(Arrays.toString(maxsubarray1));
solver solver = new solver();
long solution;
//if (args[5].equalsIgnoreCase("bruteforce")){
long startTime = System.currentTimeMillis();
solution = solver.bruteforce(maxsubarray1, n);
System.out.println("__________BRUTE FORCE________\nThe sum of the array is " + solution);
long endTime = System.currentTimeMillis() - startTime;
System.out.println(endTime);
//}
//if (args[5].equalsIgnoreCase("divideconquer")){
long startTime2 = System.currentTimeMillis();
long solutiondivideconquer = solver.divideconquer(maxsubarray2, 0, n);
System.out.println("__________DIVIDE AND CONQUERE________\nThe sum of the array is " + solutiondivideconquer);
long endTime2 = System.currentTimeMillis() - startTime2;
System.out.println(endTime2);
//}
//if (args[5].equalsIgnoreCase("dynprog")){
long startTime3 = System.currentTimeMillis();
long solutiondynprog = solver.dynprog(maxsubarray3, n);
System.out.println("__________DYNAMIC PROGRAMMING________\nThe sum of the array is " + solutiondynprog);
long endTime3 = System.currentTimeMillis() - startTime3;
System.out.println(endTime3);
//}
}
}
solver.java
public class solver {
//brute force algorithm with complexity O(n^2)
long bruteforce(long array[], int n){
long max = Long.MIN_VALUE;
//We go throght all the elements of the list and we try all the
//posible combinations with all the other elements
for (int i = 0; i < n; i++){
long sum = 0;
for (int j = i; j < n ; j++){
//we add the an element in the sum
sum += array[j];
//we check if the sum with the new element is greater that the value we had before
if(sum > max){
//if it's greater, it becomes the new value
max = sum;
}
}
}
//we return the maximum value we have found
return max;
}
//to implement the divide and conquer algorithm we have to take into account the
// maximum subarray can have elements in the right subarray and in the left subarray
long maxCrossingSum(long array[], long l, long m, long h){
long sum = 0;
long left_sum = Integer.MIN_VALUE;
//Has the elements on the left part of the arrray
for ( int i = (int)m; i >= l; i--){
sum = sum + array[i];
if( sum > left_sum ){
left_sum = sum;
}
}
sum = 0;
long right_sum = 0;
//Has the elements in the right part of the array
for ( int j = (int)m+1; j <= h; j++){
sum = sum + array [j];
if (sum > right_sum){
right_sum = sum;
}
}
//returns the sun of the elements on the left and the right of the array
return left_sum + right_sum;
}
//returns the sum of the maximum subarray
long maxSubarraySum(long array[], long l, long h){
if(l == h)
return array[1];
long m = (l + h)/2;
//checks which is the maximum between left and right
long maxBetweenLeftRight = max(maxSubarraySum(array, l, m), maxSubarraySum(array, m+1,h));
long crossing = maxCrossingSum(array, l, m,h-1);
//retrns the maximum between one of the sides and the crossing sum
return max(maxBetweenLeftRight, crossing);
}
//divide and conquere algorithm with complexity O(nlogn)
//only made to make it more understandable from the main
//can call maxSubarraySum and it would be the same
long divideconquer (long array[], int l, int h){
return maxSubarraySum(array, l, h);
}
//dynamic programming algorithm with complexity O(n)
long dynprog(long array[], int n){
long a = array[0];
long b = array[0];
//for all the elements checks if the sum was better until the
//step before or adding the element
for (int i = 1 ; i < n; i++){
a= max (a+ array[i], array[i]);
b= max(b, a);
}
return b;
}
private long max(long a, long b) {
if (a > b ) return a;
else return b;
}
}
Generator.java
import java.util.concurrent.ThreadLocalRandom;
public class Generator {
int size;
String type;
long[] generatedArray;
public Generator(int mysize, String mytype) {
size = mysize;
type = mytype;
generatedArray = new long[size];
}
public void ascending() {
for (int i = 0; i < this.size; i++)
generatedArray[i] = i + 1;
}
public void descending() {
for (int i = this.size - 1; i >= 0; i--)
generatedArray[i] = i + 1;
}
public void random() {
for (int i = 0; i <= this.size - 1; i++)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10 * this.size, 10 * this.size);
}
public void randominter() {
for (int i = 0; i <= this.size - 1; i++)
if (i % 2 == 0)
generatedArray[i] = ThreadLocalRandom.current().nextInt(1, 10 * this.size);
else if (i % 2 == 1)
generatedArray[i] = ThreadLocalRandom.current().nextInt(-10 * this.size, -1);
}
public long[] getArray() {
if (type.equalsIgnoreCase("descending")) {
this.descending();
return generatedArray;
}
if (type.equalsIgnoreCase("ascending")) {
this.ascending();
return generatedArray;
}
if (type.equalsIgnoreCase("random")) {
this.random();
return generatedArray;
}
if (type.equalsIgnoreCase("randominter")) {
this.randominter();
return generatedArray;
}
return null;
}
}
I was wrong, it CAN BE an overflow error if Array[i] = i + 1, since the sum is length * (min + max) / 2 > Integer.MAX_VALUE
Problem Statement:
Given an array of n integers, find and print its number of negative subarrays on a new line.(A subarray is negative if the total sum of its elements is negative.)
Sample Input
5
1 -2 4 -5 1
Sample Output
9
Result that my code yields
Input (stdin)
5
1 -2 4 -5 1
Your Output (stdout)
7
Expected Output
9
Compiler Message
Wrong Answer
My code:
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int a[] = new int[n];
int b[] = new int[n];
int count=0;
int i,j,sum = 0;
for(i=0;i<n;i++)
{
a[i] = scan.nextInt();
}
for(i=0;i<n;i++)
{
if(a[i]<0){count++;}
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
sum = a[i] + sum;
b[j] = sum;
}
}
for(j=0;j<n;j++)
{
if(b[j]<0){count++;}
}
System.out.println(count);
}
}
Where am I going wrong ?
Made few changes to the previous logic and now this code works fine.
import java.util.*;
public class Solution {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int a[] = new int[n];
int count=0;
int i,j,sum = 0;
for(i=0;i<n;i++)
{
a[i] = scan.nextInt();
}
scan.close();
for(i=0;i<n;i++)
{
sum = 0;
for(j=i;j<n;j++)
{
sum = a[j] + sum;
if(sum<0){
count++;
}
}
}
System.out.println(count);
}
}
a solution running in O(nlogn), based idea on counting inversion
calculate the prefix sum array of the given input, it contains cumulative sums
count the inversion in the prefix sum array when prefix[i] > prefix[j] when i < j, also count when prefix[j] < 0
the time complexity is analyzed like merge-sort
import java.util.*;
public class NegativeSumSubarray {
public static void main(String[] args) {
int[] array = { 1, -2, 4, -5, 1 };
int[] prefixSum = new int[array.length];
prefixSum[0] = array[0];
for (int i = 1; i < prefixSum.length; i++) {
prefixSum[i] = prefixSum[i - 1] + array[i];
}
int count = countInversion(prefixSum, 0, prefixSum.length - 1);
System.out.println(count); // 9
}
public static int countInversion(int[] prefixSum, int left, int right) {
// merge-sort like counting inversion in prefixSum array
if (left == right) {
if (prefixSum[left] < 0) {
return 1;
}
return 0;
}
int mid = (left + right) / 2;
int count_left = countInversion(prefixSum, left, mid);
int count_right = countInversion(prefixSum, mid + 1, right);
int count_cross = countCrossInversion(prefixSum, left, mid, right);
return count_left + count_right + count_cross;
}
public static int countCrossInversion(int[] prefixSum, int left, int mid, int right) {
List<Integer> L = new ArrayList<>();
for (int i = left; i <= mid; i++) {
L.add(prefixSum[i]);
}
L.add(Integer.MAX_VALUE);
List<Integer> R = new ArrayList<>();
for (int i = mid + 1; i <= right; i++) {
R.add(prefixSum[i]);
}
R.add(Integer.MAX_VALUE);
int count = 0;
int i = 0;
int j = 0;
for (int k = left; k <= right; k++) {
if (L.get(i) <= R.get(j)) {
prefixSum[k] = L.get(i);
i += 1;
} else {
prefixSum[k] = R.get(j);
count += L.size() - 1 - i; // size() counts additional sentinal MAX_VALUE
j += 1;
}
}
return count;
}
}
I have made this program using array concept in java. I am getting Exception as ArrayIndexOutOfBound while trying to generate product.
I made the function generateFNos(int max) to generate factors of the given number. For example a number 6 will have factors 1,2,3,6. Now,i tried to combine the first and the last digit so that the product becomes equal to 6.
I have not used the logic of finding the smallest number in that array right now. I will do it later.
Question is Why i am getting Exception as ArrayIndexOutOfBound? [i couldn't figure out]
Below is my code
public class SmallestNoProduct {
public static void generateFNos(int max) {
int ar[] = new int[max];
int k = 0;
for (int i = 1; i <= max; i++) {
if (max % i == 0) {
ar[k] = i;
k++;
}
}
smallestNoProduct(ar);
}
public static void smallestNoProduct(int x[]) {
int j[] = new int[x.length];
int p = x.length;
for (int d = 0; d < p / 2;) {
String t = x[d++] + "" + x[p--];
int i = Integer.parseInt(t);
j[d] = i;
}
for (int u = 0; u < j.length; u++) {
System.out.println(j[u]);
}
}
public static void main(String s[]) {
generateFNos(6);
}
}
****OutputShown****
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6
at SmallestNoProduct.smallestNoProduct(SmallestNoProduct.java:36)
at SmallestNoProduct.generateFNos(SmallestNoProduct.java:27)
at SmallestNoProduct.main(SmallestNoProduct.java:52)
#Edit
The improved Code using array only.
public class SmallestNoProduct {
public static void generateFNos(int max) {
int s = 0;
int ar[] = new int[max];
int k = 0;
for (int i = 1; i <= max; i++) {
if (max % i == 0) {
ar[k] = i;
k++;
s++;
}
}
for (int g = 0; g < s; g++) {
System.out.println(ar[g]);
}
smallestNoProduct(ar, s);
}
public static void smallestNoProduct(int x[], int s) {
int j[] = new int[x.length];
int p = s - 1;
for (int d = 0; d < p;) {
String t = x[d++] + "" + x[p--];
System.out.println(t);
int i = Integer.parseInt(t);
j[d] = i;
}
/*for (int u = 0; u < j.length; u++) {
System.out.println(j[u]);
}*/
}
public static void main(String s[]) {
generateFNos(6);
}
}
Maybe it better:
public class SmallestNoProduct {
public static int smallest(int n) {
int small = n*n;
for(int i = 1; i < Math.sqrt(n); i++) {
if(n%i == 0) {
int temp = Integer.parseInt(""+i+""+n/i);
int temp2 = Integer.parseInt(""+n/i+""+i);
temp = temp2 < temp? temp2: temp;
if(temp < small) {
small = temp;
}
}
}
return small;
}
public static void main(String[] args) {
System.out.println(smallest(6)); //6
System.out.println(smallest(10)); //25
System.out.println(smallest(100)); //205
}
}
Problem lies in this line
String t=x[d++]+""+x[p--];
x[p--] will try to fetch 7th position value, as p is length of array x i.e. 6 which results in ArrayIndexOutOfBound exception. Array index starts from 0, so max position is 5 and not 6.
You can refer this question regarding postfix expression.
Note: I haven't checked your logic, this answer is only to point out the cause of exception.
We are unnecessarily using array here...
below method should work....
public int getSmallerMultiplier(int n)
{
if(n >0 && n <10) // if n is 6
return (1*10+n); // it will be always (1*10+6) - we cannot find smallest number than this
else
{
int number =10;
while(true)
{
//loop throuogh the digits of n and check for their multiplication
number++;
}
}
}
int num = n;
for(i=9;i>1;i--)
{
while(n%d==0)
{
n=n/d;
arr[i++] = d;
}
}
if(num<=9)
arr[i++] = 1;
//printing array in reverse order;
for(j=i-1;j>=0;j--)
system.out.println(arr[j]);
I am trying to put java code for fibonacci search with my understanding gained from
http://en.wikipedia.org/wiki/Fibonacci_search :
Let k be defined as an element in F, the array of Fibonacci numbers. n = Fm is the array size. If the array size is not a Fibonacci number, let Fm be the smallest number in F that is greater than n.
The array of Fibonacci numbers is defined where Fk+2 = Fk+1 + Fk, when k ≥ 0, F1 = 1, and F0 = 0.
To test whether an item is in the list of ordered numbers, follow these steps:
Set k = m.
If k = 0, stop. There is no match; the item is not in the array.
Compare the item against element in Fk−1.
If the item matches, stop.
If the item is less than entry Fk−1, discard the elements from positions Fk−1 + 1 to n. Set k = k − 1 and return to step 2.
If the item is greater than entry Fk−1, discard the elements from positions 1 to Fk−1. Renumber the remaining elements from 1 to Fk−2, set k = k − 2, and return to step 2.
The below is my code:
package com.search.demo;
public class FibonacciSearch {
static int[] a = {10,20,30,40,50,60,70,80,90,100};
static int required = 70;
static int m = 2;
static int p = 0;
static int q = 0;
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
FibonacciSearch fs = new FibonacciSearch();
fs.findm();
fibSearch(required);
}
private void findm(){
//here you have to find Fm which matches size of searching array, or which is close to it.
int n = a.length;
int fibCurrent = 1;
int fibPrev1 = 1;
int fibPrev2 = 0;
while(n > fibCurrent){
fibPrev2 = fibPrev1;
fibPrev1 = fibCurrent;
fibCurrent = fibPrev1 + fibPrev2;
m++;
}
p = m-1;
q = m-2;
}
public static int fibSearch(int no){
for(;;){
if(m == 0){
System.out.println("not found");
return -1;
}
int j = f(p);
if(no == a[j]){
System.out.println("found at "+p);
}else if(no < a[j]){
m = p;
p = m - 1;
q = m - 2;
}else if(no > a[j]){
m = q; // as per the step 6..
p = m-1;
q = m-2;
}
}
//return m;
}
public static int f(int val){
if(val == 2 || val == 1 || val == 0){
return 1;
}
return (f(val-1) + f(val-2));
}
}
Please correct me what I am doing wrong, and help me understand it clearly..
I have seen this Fibonacci Search and http://www.cs.utsa.edu/~wagner/CS3343/binsearch/searches.html but I am not able to understand..
while(n > fibCurrent){
fibPrev2 = fibPrev1;
fibPrev1 = fibCurrent;
fibCurrent = fibPrev1 + fibPrev2;
m++;
}
This part in the findm() function is actually comparing nth fibonacci number but according to algorithm it should be cumulative sum of the fibonacci numbers upto that point.
Rather you can search for the element in while loop of findm.
Finally I am able to solve the puzzle, that's stopping me..
I think the below code should help someone who are stuck as I did.
package com.search.demo;
public class FibonacciSearch {
int a[] = {10,20,30,40,50,60,70,80,90,100};
static FibonacciSearch fs;
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
fs = new FibonacciSearch();
int location = fs.find(70);
if(location < 0){
System.out.println("number not found..");
}else{
System.out.println("found at location "+location);
}
}
private int find(int no){
int n = a.length;
int m = findFm(n); //m = Fm iff n is Fibonacci number else returns Fm+1
int p = fibSequenceIterative(m-1); //p = Fm-1, always a fibonacci number
int q = fibSequenceIterative(m -2); //q = Fm-2, always a fibonacci number
while(true){
if(no == a[m]){
return m;
}else if (no < a[m]){
if(q == 0){
return -(m - 1);// we crossed 0th index in array, number not found.
}
m = m - q; //moved to 1 step left towards a fibonacci num
int tmp = p;//hold this temporarily
p = q; //move p to 1 step left into another fibonacci num
q = tmp - q;//moved q to 1 step left....
}else if(no > a[m]){
if(p == 1){
return -m;//we reached 0th index in array again and number not found..
}
m = m + q;
p = p - q;
q = q - p;
}
}
}
private int findFm(int n){
int prev = 1;
int curr = 1;
int next = 0;
if(n == 0){
next = 0;
return -1;
}else if(n == 1 || n == 2){
next = 1;
return 1;
}else{
for(int i = 3; ; i++){
next = prev + curr;
prev = curr;
curr = next;
System.out.println("prev = "+prev+" curr = "+curr+" next = "+next);
if(n <= curr){
System.out.println("n = "+n+" curr = "+curr);
return i;
}
}
//return -1;//we should not get here..
}
}
/* Iterative method for printing Fibonacci sequence..*/
private int fibSequenceIterative(int n){
int prev = 1;
int curr = 1;
int next = 0;
if(n == 0){
next = 0;
//return 0;
}else if(n == 1 || n == 2){
next = 1;
//return 1;
}else{
for(int i = 3; i <= n; i++){
next = prev + curr;
prev = curr;
curr = next;
}
return next;
}
return next;
}
}
The bit of code what I am doing wrong is managing the indexes, which does influence the position of dividing the array at an index postion.
the m should be find first, to the value that matches n (size of array). if it doesn't match it should be the next value at which the F(x) will be > n. i.e., in my case size is 10 which doesn't match with any fibonacci number, so the next value in the fibonacci series is 13. and the index of i at which our condition satisfied is F(7) = 13 which is > 10. So m = 7
and now p and q are 2 consecutive fibonacci numbers which always determine the interval at which to divide the array.
read the below:
Take N = 54, so that N+1 = 55 = F[10]. We will be searching the sorted array: A[1], ..., A[54], inclusive. The array indexes are strictly between the two Fibonacci number: 0 < 55. Instead of the midpoint, this search uses the next Fibonacci number down from F[10] = 55, namely F[9] = 34. Instead of dividing the search interval in two, 50% on either side, we divide roughly by the golden ratio, roughly 62% to the left and 38% to the right. If y == A[34], then we've found it. Otherwise we have two smaller intervals to search: 0 to 34 and 34 to 55, not including the endpoints. If you have two successive Fibonacci numbers, it's easy to march backwards using subtraction, so that above, the next number back from 34 is 55 - 34 = 21. We would break up 0 to 34 with a 21 in the middle. The range from 34 to 55 is broken using the next Fibonacci number down: 34 - 21 = 13. The whole interval [34, 55] has length 21, and we go 13 past the start, to 34 + 13 = 47. Notice that this is not a Fibonacci number -- it's the lengths of all the intervals that are.(copied from http://www.cs.utsa.edu/~wagner/CS3343/binsearch/fibsearch.html)