dragon curve with L system using recursion in java - java

I want to compute dragon curve till n = 10 in java with L system using recursion. For example,
Replace all F characters with F-H
Replace all H characters with F+H
dragon(0) = F-H (this is the input)
dragon(1) = F-H-F+H
dragon(2) = F-H-F+H-F-H+F+H
...
dragon(10) = ?
How can I accomplish the same in java using recursion? I'm only interested in knowing the recursive approach.

In recursive approach such "replace" problem statements usually can be implemented as recursive calls.
So let's create two functions - F() and H() each of them will return "F" or "H" when desired curve depth is reached, or F(...) + "-" + H(...) or F(...) + "+" + H(...) if further expansion is needed.
private String F(int depth) {
if (depth == 0) {
return "F";
} else {
return F(depth - 1) + "-" + H(depth - 1);
}
}
private String H(int depth) {
if (depth == 0) {
return "H";
} else {
return F(depth - 1) + "+" + H(depth - 1);
}
}
public String dragon(int depth) {
return F(depth + 1);
}
Try it online!

Related

integer to word conversion in java using map continue question

This is a probable answer of my question in stack overflow.Integer to word conversion
At first I have started with dictionary. Then I came to know it is obsolete. So now I use Map instead of dictionary. My code is work well for number till Millions. But the approach I take here is a naive approach. The main problem of this code is
First: Huge numbers of variable use
2nd: Redundant code block as per program requirement
3rd: Multiple if else statement
I am thinking about this problems
Solution for 2nd problem: using user define function or macros to eliminate redundant code block
Solution for 3rd problem: Using switch case
My code:
public class IntegerEnglish {
public static void main(String args[]){
Scanner in=new Scanner(System.in);
System.out.println("Enter the integer");
int input_number=in.nextInt();
Map<Integer,String> numbers_converter = new HashMap<Integer,String>();
Map<Integer,String> number_place = new HashMap<Integer,String>();
Map<Integer,String> number_2nd = new HashMap<Integer,String>();
numbers_converter.put(0,"Zero");
numbers_converter.put(1,"One");
numbers_converter.put(2,"Two");
numbers_converter.put(3,"Three");
numbers_converter.put(4,"Four");
numbers_converter.put(5,"Five");
numbers_converter.put(6,"Six");
numbers_converter.put(7,"Seven");
numbers_converter.put(8,"Eight");
numbers_converter.put(9,"Nine");
numbers_converter.put(10,"Ten");
numbers_converter.put(11,"Eleven");
numbers_converter.put(12,"Twelve");
numbers_converter.put(13,"Thirteen");
numbers_converter.put(14,"Fourteen ");
numbers_converter.put(15,"Fifteen");
numbers_converter.put(16,"Sixteen");
numbers_converter.put(17,"Seventeen");
numbers_converter.put(18,"Eighteen");
numbers_converter.put(19,"Nineteen");
number_place.put(3,"Hundred");
number_place.put(4,"Thousand");
number_place.put(7,"Million");
number_place.put(11,"Billion");
number_2nd.put(2,"Twenty");
number_2nd.put(3,"Thirty");
number_2nd.put(4,"Forty");
number_2nd.put(5,"Fifty");
number_2nd.put(6,"Sixty");
number_2nd.put(7,"Seventy");
number_2nd.put(8,"Eighty");
number_2nd.put(9,"Ninty");
if(input_number== 0){
System.out.println("zero");
}
else if(input_number>0 && input_number<19){
System.out.println(numbers_converter.get(input_number));
}
else if(input_number>19 && input_number<100){
int rem=input_number%10;
input_number=input_number/10;
System.out.print(number_2nd.get(input_number));
System.out.print(numbers_converter.get(rem));
}
else if(input_number==100){
System.out.println(number_place.get(3));
}
else if(input_number>100 && input_number<1000){
int reminder=input_number%100;
int r1=reminder%10;
int q1=reminder/10;
int quot=input_number/100;
System.out.print(numbers_converter.get(quot) + "hundred");
if(reminder>0 && reminder<20){
System.out.print(numbers_converter.get(reminder));
}
else{
System.out.println(number_2nd.get(q1) + numbers_converter.get(r1));
}
}
else if(input_number==1000){
System.out.println(number_place.get(4));
}
else if(input_number>1000 && input_number<10000){
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
System.out.print(numbers_converter.get(thousand) + "thousand" + numbers_converter.get(hundred)+ " hundred");
if(rem >0 && rem<20){
System.out.print(numbers_converter.get(rem));
}
else if(rem >19 && rem <100){
System.out.print(number_2nd.get(quotient) + numbers_converter.get(rem_two));
}
}
else if(input_number>10000 && input_number<1000000000){
//Say number 418,229,356
int third_part=input_number%1000;//hold 356
input_number=input_number/1000;//hold 418,229
int sec_part=input_number%1000;//hold 229
input_number=input_number/1000;// hold 418
int rem_m=third_part%100;//hold 56
int rem_m1=rem_m%10;//hold 6
int rem_q=rem_m/10;// hold 5
int q_m=third_part/100;// hold 3
int sec_part_rem=sec_part%100;// hold 29
int sec_part_rem1=sec_part_rem%10;//9
int sec_part_q=sec_part_rem/10;//hold 2
int sec_q=sec_part/100;// hold 2
int input_q=input_number/100;// hold 4
int input_rem=input_number%100;//hold 18
int input_q_q=input_rem/10;//hold 1
int input_rem1=input_rem%10;// hold 8
System.out.print(numbers_converter.get(input_q) + " hundred ");
if(input_rem>0 && input_rem<20){
System.out.print(numbers_converter.get(input_rem)+ " Million ");
}
else{
System.out.print(number_2nd.get(input_q_q) + " " + numbers_converter.get(input_rem1) + " Million ");
}
System.out.print(numbers_converter.get(sec_q) + " hundred ");
if(sec_part_rem >0 && sec_part_rem<20){
System.out.println(numbers_converter.get(sec_part_rem) + " thousand ");
}
else{
System.out.print(number_2nd.get(sec_part_q) + " " + numbers_converter.get(sec_part_rem1) + " thousand ");
}
System.out.print(numbers_converter.get(q_m) + " hundred ");
if(rem_m>0 && rem_m<20){
System.out.print(numbers_converter.get(rem_m));
}
else{
System.out.print(number_2nd.get(rem_q) + " " + numbers_converter.get(rem_m1));
}
}
}
}
Redundant Code Blocks
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
This type of code block used almost every where. Taking a number divide it with 100 or 1000 to find out the hundred position then then divide it with 10 to find out the tenth position of the number. Finally using %(modular division) to find out the ones position.
How could I include user define function and switch case to minimize the code block.
Instead of storing the results in variables, use a method call:
int remainder100(int aNumber) {
return aNumber % 100;
}
int remainder10(int aNumber) {
return aNumber % 10;
}
...etc.
System.out.println(numbers_converter.get(remainder100(input_number)));
About 3rd problem: I wouldn't use switch ... case, too many cases.
Instead, take advantage that numbering repeats itself every 3 digits. That means the pattern for thousands and millions is the same (and billions, trillions, etc).
To do that, use a loop like this:
ArrayList<String> partialResult = new ArrayList<String>();
int powersOf1000 = 0;
for (int kiloCounter = input_number; kiloCounter > 0; kiloCounter /= 1000) {
partialResult.add(getThousandsMilionsBillionsEtc(powersOf1000++);
partialResult.add(convertThreeDigits(kiloCounter % 1000));
}
Then you can print out the contents of partialResult in reverse order to get the final number.
I'd suggest you break your single main method down into a couple of classes. And if you haven't already create a few unit tests to allow you to easily test / refactor things. You'll find it quicker than starting the app and reading from stdin.
You'll find it easier to deal with the number as a string. Rather than dividing by 10 all the time you just take the last character of the string. You could have a class that does that bit for you, and a separate one that does the convert.
Here's what I came up with, but I'm sure it can be improved. It has a PoppableNumber class which allows the last character of the initial number to be easily retrieved. And the NumberToString class which has a static convert method to perform the conversion.
An example of a test would be
#Test
public void Convert102356Test() {
assertEquals("one hundred and two thousand three hundred and fifty six", NumberToString.convert(102356));
}
And here's the NumberToString class :
import java.util.HashMap;
import java.util.Map;
public class NumberToString {
// billion is enough for an int, obviously need more for long
private static String[] power3 = new String[] {"", "thousand", "million", "billion"};
private static Map<String,String> numbers_below_twenty = new HashMap<String,String>();
private static Map<String,String> number_tens = new HashMap<String,String>();
static {
numbers_below_twenty.put("0","");
numbers_below_twenty.put("1","one");
numbers_below_twenty.put("2","two");
numbers_below_twenty.put("3","three");
numbers_below_twenty.put("4","four");
numbers_below_twenty.put("5","five");
numbers_below_twenty.put("6","six");
numbers_below_twenty.put("7","seven");
numbers_below_twenty.put("8","eight");
numbers_below_twenty.put("9","nine");
numbers_below_twenty.put("10","ten");
numbers_below_twenty.put("11","eleven");
numbers_below_twenty.put("12","twelve");
numbers_below_twenty.put("13","thirteen");
numbers_below_twenty.put("14","fourteen ");
numbers_below_twenty.put("15","fifteen");
numbers_below_twenty.put("16","sixteen");
numbers_below_twenty.put("17","seventeen");
numbers_below_twenty.put("18","eighteen");
numbers_below_twenty.put("19","nineteen");
number_tens.put(null,"");
number_tens.put("","");
number_tens.put("0","");
number_tens.put("2","twenty");
number_tens.put("3","thirty");
number_tens.put("4","forty");
number_tens.put("5","fifty");
number_tens.put("6","sixty");
number_tens.put("7","seventy");
number_tens.put("8","eighty");
number_tens.put("9","ninty");
}
public static String convert(int value) {
if (value == 0) {
return "zero";
}
PoppableNumber number = new PoppableNumber(value);
String result = "";
int power3Count = 0;
while (number.hasMore()) {
String nextPart = convertUnitTenHundred(number.pop(), number.pop(), number.pop());
nextPart = join(nextPart, " ", power3[power3Count++], true);
result = join(nextPart, " ", result);
}
if (number.isNegative()) {
result = join("minus", " ", result);
}
return result;
}
public static String convertUnitTenHundred(String units, String tens, String hundreds) {
String tens_and_units_part = "";
if (numbers_below_twenty.containsKey(tens+units)) {
tens_and_units_part = numbers_below_twenty.get(tens+units);
}
else {
tens_and_units_part = join(number_tens.get(tens), " ", numbers_below_twenty.get(units));
}
String hundred_part = join(numbers_below_twenty.get(hundreds), " ", "hundred", true);
return join(hundred_part, " and ", tens_and_units_part);
}
public static String join(String part1, String sep, String part2) {
return join(part1, sep, part2, false);
}
public static String join(String part1, String sep, String part2, boolean part1Required) {
if (part1 == null || part1.length() == 0) {
return (part1Required) ? "" : part2;
}
if (part2.length() == 0) {
return part1;
}
return part1 + sep + part2;
}
/**
*
* Convert an int to a string, and allow the last character to be taken off the string using pop() method.
*
* e.g.
* 1432
* Will give 2, then 3, then 4, and finally 1 on subsequent calls to pop().
*
* If there is nothing left, pop() will just return an empty string.
*
*/
static class PoppableNumber {
private int original;
private String number;
private int start;
private int next;
PoppableNumber(int value) {
this.original = value;
this.number = String.valueOf(value);
this.next = number.length();
this.start = (value < 0) ? 1 : 0; // allow for minus sign.
}
boolean isNegative() {
return (original < 0);
}
boolean hasMore() {
return (next > start);
}
String pop() {
return hasMore() ? number.substring(--next, next+1) : "";
}
}
}

Regular Expression for numerals in java

In my application I need filter concept for numeric.So I need to generate dynamic regular expression format.For example if I gave input is like (attrN = number,operator="equal",value=459) and (attrN = number,operator="lessthan equal",value=57) and (attrN = number,operator="not equal",value=45) and (attrN = number,operator="greaterthan equal",value=1000).based on the above conditions need to develop dynamic regular expression.I tried lessthan equal condition but I didn't get union and subtraction also greater than equal conditions.I need the logic or algorithm.
public class NumericRangeRegex {
public String baseRange(String num, boolean up, boolean leading1) {
char c = num.charAt(0);
char low = up ? c : leading1 ? '1' : '0';
char high = up ? '9' : c;
if (num.length() == 1)
return charClass(low, high);
String re = c + "(" + baseRange(num.substring(1), up, false) + ")";
if (up) low++; else high--;
if (low <= high)
re += "|" + charClass(low, high) + nDigits(num.length() - 1);
return re;
}
private String charClass(char b, char e) {
return String.format(b==e ? "%c" : e-b>1 ? "[%c-%c]" : "[%c%c]", b, e);
}
private String nDigits(int n) {
return nDigits(n, n);
}
private String nDigits(int n, int m) {
return "[0-9]" + String.format(n==m ? n==1 ? "":"{%d}":"{%d,%d}", n, m);
}
private String eqLengths(String from, String to) {
char fc = from.charAt(0), tc = to.charAt(0);
if (from.length() == 1 && to.length() == 1)
return charClass(fc, tc);
if (fc == tc)
return fc + "("+rangeRegex(from.substring(1), to.substring(1))+")";
String re = fc + "(" + baseRange(from.substring(1), true, false) + ")|"
+ tc + "(" + baseRange(to.substring(1), false, false) + ")";
if (++fc <= --tc)
re += "|" + charClass(fc, tc) + nDigits(from.length() - 1);
return re;
}
private String nonEqLengths(String from, String to) {
String re = baseRange(from,true,false) + "|" + baseRange(to,false,true);
if (to.length() - from.length() > 1)
re += "|[1-9]" + nDigits(from.length(), to.length() - 2);
return re;
}
public String run(int n, int m) {
return "\\b0*?("+ rangeRegex("" + n, "" + m) +")\\b";
}
public String rangeRegex(String n, String m) {
return n.length() == m.length() ? eqLengths(n, m) : nonEqLengths(n, m);
}
}
Use a simple interface for this
public interface Check {
boolean isValidFor(int value);
}
Then implement different classes for different kind of checks like
public class isEqualTo implements Check {
private int valueToTestAgainst;
public isEqualTo(int test) {
valueToTestAgainst = test;
}
public boolean isValidFor(int value) {
return valueToTestAgainst == value;
}
}
public class isGreatherThan implements Check {
private int valueToTestAgainst;
public isGreatherThan(int test) {
valueToTestAgainst = test;
}
public boolean isValidFor(int value) {
return valueToTestAgainst > value;
}
}
And then have a class that parses the given input and creates a list of Check objects. Maybe create an abstract class to hold the check value (valueToTestAgainst) and/or make the implementation generic to support other types like double.
Based on conditions Ill try for union and subtraction is `^(?!250)0*?([0-9]|2(5([0-5])|[0-4][0-9])|1[0-9]{2}|[1-9][0-9]|2000)$. In this we are matching 1 to 255 range and 2000 numeric number(union) and for negate 250(subtraction).It's working fine.

How to build the case for n=3 using bottom up recursion?

I am working on a problem from Cracking the Coding Interview, problem 9.6 page 110.
Here is the problem:
Implement an algorithm to print all valid (e.g., properly opened and closed combinations of n-pairs of parentheses. Examples
b(1) - "()"
b(2) - "(()), ()()"
b(3) - "((())), (()()), (())(), ()(()), ()()()"
I am trying to use the bottom up recursion approach that the author discusses on page 107 - "We start with knowing how to solve the problem for a simple case, like a list with only one element, and figure out how to solve the problem for two elements, then for three elements, and so on. The key here is to think about how you can build the solution for one case off the previous case"
Here is the code I have so far
static void print(int n) {
print(n, new HashSet<String>(), "", "");
}
static void print(int n, Set<String> combs, String start, String end) {
if(n == 0) {
if(!combs.contains(start + end)) {
System.out.print(start + end);
combs.add(start + end);
}
} else {
print(n-1, combs, "(" + start, end +")");
System.out.print(", ");
print(n-1, combs, start, end + "()");
System.out.print(", ");
print(n-1, combs, "()" + start, end);
}
}
To get this code, I worked from the first case to the second case. I saw that b(2) = "(b(1)), b(1),b(1)"
This code does work for the first two cases. I am really struggling with the third case though. Can someone give me a hint(not the whole answer, could turn to the back of the book for that), about how to go from case 2 to case 3, or in other words using case 2 to get to case 3? Like how would you go from (()), ()() to ((())), (()()), (())(), ()(()), ()()()? Would you abandon the pattern you saw from b(1) to b(2) because it doesn't work for b(2) to b(3)?
We can generate from b(n) to b(n + 1) by using this recursive formula:
(b(n - x))b(x) with 0 <= x <= n
So, you can have all of your combinations by iterating through all x.
Code:
public static ArrayList<String> cal(int num){
if(num == 0){
ArrayList<String> list = new ArrayList();
list.add("");
return list;
}else{
ArrayList<String>result = new ArrayList();
for(int i = 0; i <= num - 1; i++){
ArrayList<String> a = cal(i);
ArrayList<String> b = cal(num - 1 - i);
for(String x : a){
for(String y : b){
result.add("(" + x + ")" + y);
}
}
}
return result;
}
}
Input: 3
Output: ()()(), ()(()), (())(), (()()), ((()))
Input: 4
Output: ()()()(), ()()(()), ()(())(), ()(()()), ()((())), (())()(), (())(()), (()())(), ((()))(), (()()()), (()(())), ((())()), ((()())), (((())))
Thanks Khanna111 for pointing out the mistake I made in my original answer, which was incomplete and under-counted the string patterns. As a result, I have updated my answer accordingly.
Please consider giving credit to Pham Trung for his answer with the correct recursive formula. My answer is essentially the same as his, with only a slight difference in the way I formulate the construction of patterns from smaller sub-problems (as I find it easier to explain the details in my approach).
========================================================================
Update Solution
For any valid pattern s of size n, s falls in exactly one of the following cases:
Case 1: s cannot be partitioned into two valid patterns of smaller size
Case 2: s can be partitioned into two valid patterns of smaller size
For case 1, s must be of the form (_____), where _____ is a valid pattern of size n - 1. So in this case, for every valid pattern t of size n - 1, we simply construct a pattern s by concatenating t with ( and ) as prefix and suffix, respectively (i.e. s = (t)).
For case 2, we can partition s into uv, where u and v are both valid patterns of smaller size. In this case, we have to consider all possible patterns of u and v, where u can be any valid pattern of size i = 1, 2, ..., n - 1, while v can be any valid pattern of size n - i.
When n = 0, clearly only the empty string is a valid pattern, so we have dp(0) = { "" } as our base case. A complete implementation with caching to improve the performance is given below:
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class BalancingBrackets {
private static Map<Integer, Set<String>> dp = new HashMap<>();
public static void main(String[] args) {
Set<String> result = compute(4);
boolean isFirst = true;
for (String s : result) {
if (isFirst) {
isFirst = false;
System.out.print(s);
} else {
System.out.print(", " + s);
}
}
}
private static Set<String> compute(Integer n) {
// Return the cached result if available
if (dp.containsKey(n)) {
return dp.get(n);
}
Set<String> set = new HashSet<>();
if (n == 0) {
// This is the base case with n = 0, which consists only of the
// empty string
set.add("");
} else if (n > 0) {
// For generating patterns in case 1
for (String s : compute(n - 1)) {
set.add("(" + s + ")");
}
// For generating patterns in case 2
for (int i = 1; i < n; i++) {
Set<String> leftPatterns = compute(i);
Set<String> rightPatterns = compute(n - i);
for (String l : leftPatterns) {
for (String r : rightPatterns) {
set.add(l + r);
}
}
}
} else {
// Input cannot be negative
throw new IllegalArgumentException("Input cannot be negative.");
}
// Cache the solution to save time for computing large size problems
dp.put(n, set);
return set;
}
}

Convert recursive function into the non-recursive function

Is it possible to convert the function go into the non-recursive function? Some hints or a start-up sketch would be very helpful
public static TSPSolution solve(CostMatrix _cm, TSPPoint start, TSPPoint[] points, long seed) {
TSPSolution sol = TSPSolution.randomSolution(start, points, seed, _cm);
double t = initialTemperature(sol, 1000);
int frozen = 0;
System.out.println("-- Simulated annealing started with initial temperature " + t + " --");
return go(_cm, sol, t, frozen);
}
private static TSPSolution go(CostMatrix _cm, TSPSolution solution, double t, int frozen) {
if (frozen >= 3) {
return solution;
}
i++;
TSPSolution bestSol = solution;
System.out.println(i + ": " + solution.fitness() + " " + solution.time() + " "
+ solution.penalty() + " " + t);
ArrayList<TSPSolution> nHood = solution.nHood();
int attempts = 0;
int accepted = 0;
while (!(attempts == 2 * nHood.size() || accepted == nHood.size()) && attempts < 500) {
TSPSolution sol = nHood.get(rand.nextInt(nHood.size()));
attempts++;
double deltaF = sol.fitness() - bestSol.fitness();
if (deltaF < 0 || Math.exp(-deltaF / t) > Math.random()) {
accepted++;
bestSol = sol;
nHood = sol.nHood();
}
}
frozen = accepted == 0 ? frozen + 1 : 0;
double newT = coolingSchedule(t);
return go(_cm, bestSol, newT, frozen);
}
This is an easy one, because it is tail-recursive: there is no code between the recursive call & what the function returns. Thus, you can wrap the body of go in a loop while (frozen<3), and return solution once the loop ends. And replace the recursive call with assignments to the parameters: solution=bestSol; t=newT;.
You need to thinkg about two things:
What changes on each step?
When does the algorithm end?
Ans the answer should be
bestSol (solution), newT (t), frozen (frozen)
When frozen >= 3 is true
So, the easiest way is just to enclose the whole function in something like
while (frozen < 3) {
...
...
...
frozen = accepted == 0 ? frozen + 1 : 0;
//double newT = coolingSchedule(t);
t = coolingSchedule(t);
solution = bestSol;
}
As a rule of thumb, the simplest way to make a recursive function iterative is to load the first element onto a Stack, and instead of calling the recursion, add the result to the Stack.
For instance:
public Item recursive(Item myItem)
{
if(myItem.GetExitCondition().IsMet()
{
return myItem;
}
... do stuff ...
return recursive(myItem);
}
Would become:
public Item iterative(Item myItem)
{
Stack<Item> workStack = new Stack<>();
while (!workStack.isEmpty())
{
Item workItem = workStack.pop()
if(myItem.GetExitCondition().IsMet()
{
return workItem;
}
... do stuff ...
workStack.put(workItem)
}
// No solution was found (!).
return myItem;
}
This code is untested and may (read: does) contain errors. It may not even compile, but should give you a general idea.

Find Range of a number from an array

I'm just rephrasing the question I asked a little while ago.
I have a sorted array {2.0,7.8,9.0,10.5,12.3}
If I given an input 9.5
What is the fastest way to find 9.0 and 10.5 to indicate that 9.5 is in between 9.0 and 10.5 (9.5 >=9.0 and <10.5) ?
Is binary search an option?But since the input need not be in the array.I'm not sure how I should do this.
Also If there is any other data structure that is suitable please comment.
A binary search would certainly be the "standard" approach - http://en.wikipedia.org/wiki/Binary_search_algorithm. Speed is O(log(N)) as opposed to linear.
In certain specialised cases you can do better than O(log(N)). But unless you are dealing with truly gigantic array sizes and satisfy these special cases then your binary search is really the fastest approach.
You could use Arrays.binarySearch to quickly locate 9.0 and 10.0, indeed.
Here's a binary search algorithm I just wrote for you that does the trick:
import java.util.Random;
public class RangeFinder {
private void find(double query, double[] data) {
if (data == null || data.length == 0) {
throw new IllegalArgumentException("No data");
}
System.out.print("query " + query + ", data " + data.length + " : ");
Result result = new Result();
int max = data.length;
int min = 0;
while (result.lo == null && result.hi == null) {
int pos = (max - min) / 2 + min;
if (pos == 0 && query < data[pos]) {
result.hi = pos;
} else if (pos == (data.length - 1) && query >= data[pos]) {
result.lo = pos;
} else if (data[pos] <= query && query < data[pos + 1]) {
result.lo = pos;
result.hi = pos + 1;
} else if (data[pos] > query) {
max = pos;
} else {
min = pos;
}
result.iterations++;
}
result.print(data);
}
private class Result {
Integer lo;
Integer hi;
int iterations;
long start = System.nanoTime();
void print(double[] data) {
System.out.println(
(lo == null ? "" : data[lo] + " <= ") +
"query" +
(hi == null ? "" : " < " + data[hi]) +
" (" + iterations + " iterations in " +
((System.nanoTime() - start) / 1000000.0) + " ms. )");
}
}
public static void main(String[] args) {
RangeFinder rangeFinder = new RangeFinder();
// test validation
try {
rangeFinder.find(12.4, new double[] {});
throw new RuntimeException("Validation failed");
} catch (IllegalArgumentException e) {
System.out.println("Validation succeeded");
}
try {
rangeFinder.find(12.4, null);
throw new RuntimeException("Validation failed");
} catch (IllegalArgumentException e) {
System.out.println("Validation succeeded");
}
// test edge cases with small data set
double[] smallDataSet = new double[] { 2.0, 7.8, 9.0, 10.5, 12.3 };
rangeFinder.find(0, smallDataSet);
rangeFinder.find(2.0, smallDataSet);
rangeFinder.find(7.9, smallDataSet);
rangeFinder.find(10.5, smallDataSet);
rangeFinder.find(12.3, smallDataSet);
rangeFinder.find(10000, smallDataSet);
// test performance with large data set
System.out.print("Preparing large data set...");
Random r = new Random();
double[] largeDataSet = new double[20000000];
largeDataSet[0] = r.nextDouble();
for (int n = 1; n < largeDataSet.length; n++) {
largeDataSet[n] = largeDataSet[n - 1] + r.nextDouble();
}
System.out.println("done");
rangeFinder.find(0, largeDataSet);
rangeFinder.find(5000000.42, largeDataSet);
rangeFinder.find(20000000, largeDataSet);
}
}
I would do it like that
double valuebefore = 0;
double valueafter = 0;
double comparevalue = 9;
foreach (var item in a)
{
valueafter = item;
if (item > comparevalue)
{
break;
}
valuebefore = item;
}
System.Console.WriteLine("Befor = {0} After = {1}", valuebefore, valueafter);
If the input numbers are in an array then binary search will be handy. Every time the search fails, indicating the number is not present in the array, the array elements at index low and high will give you the range.
The most efficient (space and time-wise) is to implement this as a modified binary search.
A simple (but less efficient) solution is to replace the array with a NavigableMap<Double, Double> and use floorKey and ceilingKey to find the bounding values. Assuming that you use a TreeMap, this has the same complexity as binary search.
For small numbers of bins a sorted linked list will be most elegant. You scan over it and when you find a number bigger you have the range.
For very large numbers it is worth putting them in a BTree or similar Tree structure in order to get O(log(N)) performance.
In Java you can use a TreeSet for this.
lowerBound = boundaries.headSet(yourNumber).last();
upperBound = boundaries.tailSet(yourNumber).first();
or similar will be O(logN) for large numbers.

Categories