Related
I have a number (int y = 12345). I want to find how I can shuffle y to find the number that is the middle of all possible combinations that can be made when shuffling. In this case, the answer would be 32541.
I initially tried to put 1,2,3,4,5 in a list and use Collections.shuffle to get all options and put them in a sortedSet. Then get the index at size()/2. But this doesn't work well for numbers larger than 123456789...
I also tried to use recursion to switch around all the numbers using heap's algorithm. That worked slightly better, but still couldn't process large numbers. See below. (I switched the integer to a string abcdefghij)
public static SortedSet<String> allStrings = new TreeSet<>();
public static SortedSet<String> findMidPerm(String strng) {
permutation("", strng);
return allStrings;
}
private static void permutation(String prefix, String str) {
int n = str.length();
if (n == 0) {
allStrings.add(prefix);
} else {
for (int i = 0; i < n; i++)
permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i + 1, n));
}
}
public static void main(String[] args) {
System.out.println(findMidPerm("abcdefghij"));
}
My current idea is to not create all possible numbers, but find the exact center of all possible combinations (int x = 33333). And then see which combination of numbers is closest to that number. In this case, this is either 32541 OR 34125. Both numbers are 792 steps away from x.
This is what I have so far:
public static float findMidPerm(String strng) {
float maxNum = findMaxNum(strng);
float minNum = findMinNum(strng);
float middleNum = findMiddleNum(minNum, maxNum);
return middleNum;
}
private static float findMiddleNum(float minNum, float maxNum) {
return (minNum+maxNum)/2;
}
private static float findMinNum(String strng) {
String s = "";
for (int i = 0; i <= strng.length(); i ++) {
s += i;
}
return Float.parseFloat(s);
}
private static Float findMaxNum(String strng) {
String s = "";
for (int i = strng.length(); i> 0; i --) {
s += i;
}
return Float.parseFloat(s);
}
public static void main(String[] args) {
System.out.println(findMidPerm("abcdefghijklmnop"));
}
Now for the difficult part of creating the algorithm that finds the order of integers closest to x. Does anyone have any ideas how this can be achieved?
(This is an answer to the original problem, how to find the median of all permutations, not for the XY-problem, how to find the permutation closest to a given number.)
I think, if you want to find exactly the median of the permutations, there is good and bad news: Good news: There seems to be an easy algorithm for that. Bad news: There is no exact median, as the number of permutations is always even (as it is 1 x 2 x 3 x ... x n)
Sort the input number so the digits are in ascending order
If the number has an odd number of digits, pick the middle digit as the first digit
The number now has an even number of digits; you have to pick either of the two middle digits, but this will skew the result (see the bad news above)
If you picked the lower of the middle digits, form the largest possible number from the remaining digits, otherwise the lowest possible number.
For your example: 12345 -> 3 1245 --> 32 145 --> 32541, or 12345 -> 3 1245 --> 34 125 --> 34125.
The intuition behind this is as follows: You can subdivide the n! (sorted) permutations of a number with n digits into n groups, each starting with the ith digit and having (n-1)! elements. As those groups are ordered, and each has the same number of elements, the median has to be in the middle group for an odd-numbered input, and right in between the middle two groups for an even-numbered input. So you have to pick either the largest of the smaller, or the smallest of the larger middle group. (And for an odd-numbered input, do the same for the n-1 sub-groups of the middle group.)
Here's a sample code (in Python, because I'm too lazy...)
# above algorithm
def med_perm(n):
lst = sorted(str(n)) # step 1
res = [lst.pop(len(lst)//2)] if len(lst) % 2 == 1 else [] # step 2
res.append(lst.pop(len(lst)//2)) # step 3
res.extend(lst) # step 4
return int(''.join(res))
# for reference
import itertools
def med_perm2(n):
perms = list(map(''.join, itertools.permutations(sorted(str(n)))))
return int(perms[len(perms)//2])
# testing
import random
n = random.randint(1, 100000000)
x, y = med_perm(n), med_perm2(n)
print(n, x, y, x==y)
I actually found a sneaky way to do this. I was writing everything down on paper and recognized a pattern. This is the first draft of the code and it can probably be done way more efficient. Feel free to adjust!
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Kata {
public static String findMidPerm(String strng) {
strng = sortString(strng);
StringBuilder sb = new StringBuilder();
List<Integer> s = createNum(strng);
for(int i =0; i <s.size(); i++) {
int b = s.get(i);
sb.append(strng.charAt(b-1));
}
return sb.toString();
}
private static String sortString(String strng) {
char[] ar = strng.toCharArray();
Arrays.sort(ar);
String sorted = String.valueOf(ar);
return sorted;
}
public static List<Integer> createNum(String strng) {
List<Integer> list = new ArrayList<>();
int s = strng.length() / 2;
int s2 = (strng.length() / 2) + 1;
if (strng.length() % 2 == 0) {
list.add(s);
for (int i = strng.length(); i > 0; i--)
if (i != s) {
list.add(i);
}
} else {
list.add(s2);
list.add(s);
for (int i = strng.length(); i > 0; i--)
if (i != s && i != s2) {
list.add(i);
}
}
return list;
}
public static void main(String[] args) {
System.out.println(findMidPerm("cmafilezoysht")); // cmafilezoysht is an input string in this case.
}
}
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 am trying to solve a problem in which you have to count the number of possible bar codes you can make given specific parameters. I solved the problem recursively and am able to get the correct answer every time. However, my program is dreadfully slow. I tried to rectify this using a technique I read about called memoization but my program still crawls when given certain input (ex: 10, 10, 10). Here's the code in java.
Does anybody have any idea what I'm doing wrong here?
import java.util.Scanner;
//f(n, k, m) = sum (1 .. m) f(n - i, k - 1, m)
public class BarCode { public static int[][] memo;
public static int count(int units, int bars, int width) {
int sum = 0;
if (units >= 0 && memo[units][bars] != -1) //if the value has already been calculated return that value
return memo[units][bars];
for (int i = 1; i <= width; ++i) {
if (units == 0 && bars == 0)
return 1;
else if (bars == 0)
return 0;
else {
sum += count(units - i, bars - 1, width);
}
}
if (units > -1)
memo[units][bars] = sum;
return sum;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
//while (in.hasNext()) {
int num = in.nextInt();
int bars = in.nextInt();
int width = in.nextInt();
memo = new int[51][51];
for (int i = 0; i < memo.length; ++i) {
for (int j = 0; j < memo.length; ++j)
memo[i][j] = -1;
}
int sum = 0;
sum += count(num, bars, width);
System.out.println(sum);
//}
in.close();
}
}
TL:DR My memoization of a recursive search is too slow. Help!
You exclude all results from count calls with units < 0 from memoization:
if (units > -1)
memo[units][bars] = sum;
This leads to a lot of unnecessary calls to count for these values.
To include all cases, you could use a HashMap with a key generated from units and bars values. I used a string generated from units and bars like this:
//f(n, k, m) = sum (1 .. m) f(n - i, k - 1, m)
public class BarCode {
public static Map<String, Integer> memo = new HashMap<>();
public static int count(int units, int bars, int width) {
int sum = 0;
final String key = units + " " + bars;
Integer memoSum = memo.get(key);
if (memoSum != null) {
return memoSum.intValue();
}
for (int i = 1; i <= width; ++i) {
if (units == 0 && bars == 0)
return 1;
else if (bars == 0)
return 0;
else {
sum += count(units - i, bars - 1, width);
}
}
memo.put(key, Integer.valueOf(sum));
return sum;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int num = in.nextInt();
int bars = in.nextInt();
int width = in.nextInt();
memo = new HashMap<>();
int sum = 0;
sum += count(num, bars, width);
System.out.println(sum);
in.close();
}
}
For example, this brings the number of calls to count down from over 6 million to 4,150 for the input values "10 10 10" with 415 entries saved in the Map.
Your memoization implementation looks to be valid. It might help some, but the real problem here is your choice of algorithm.
From my cursory inspection of your code, on average a call to your count method will loop through width number of times. and each time it loops through, it goes a layer deeper by calling count again. It also looks like it's going to loop down bars layers deeper from the first layer. If my asymptotic analysis a few fingers of scotch in is correct, this would result in an algorithm which has a O(width^bars) runtime complexity. As you increase your input parameters, especially bars, the amount of steps your application needs to take in order to calculate your answer will increase greatly (exponentially, in the case of bars).
Your memoization will reduce the number of duplicate calculations needed, but each value being memoized will still need to be calculated at least once for the memoization to help. So with or without the memoization, you're still dealing with a non-polynomial time complexity, and that always spells bad performance.
You might want to consider looking for a more efficient approach. Instead of trying to count the number of bar code combinations, perhaps try using combinatorics to try to calculate it. For example, I could try to figure out the number of lowercase character strings (using only chars a-z) I can make for a string of length n by generating all of them and counting how many of them there are, but that will have an exponential time complexity and will not be performant. On the other hand, I know basic combinatorics tells me that the formula for the number of strings I can create is 26^n (26 choices in each position, and n positions), which the computer can easily evaluate quickly.
Look for a similar approach for computing the number of bar codes.
I recently made a very simple practice program in Python, that takes user input and rolls dice. The code is:
import random
import sys
import math
def roll(rolls, sides, results):
for rolls in range(1, rolls + 1):
result = random.randrange(1, sides + 1)
print result
results.append(result)
def countf(rolls, sides, results):
i = 1
print "There were", rolls, "rolls."
for sides in range(1, sides + 1):
if results.count(i) != 1:
print "There were", results.count(i), i,"s."
else:
print "There was", results.count(i), i
i = i + 1
if i == sides:
break
rolls = input("How many rolls? ")
sides = input("How many sides of the die? ")
results = []
roll(rolls, sides, results)
countf(rolls, sides, results)
(actually this is part of a larger program, so I had to cut'n'paste bits, and I might have missed something out).
And so I decided to translate that to Java. Notice the algorithm here: get random number, print it, append it to an array, then count the amount of each number in the array at the end, and print out that value. Problem is, I don't know how to do the equivalent of someArray.count(someIndex) in Java syntax. So my Java program looks like this so far:
import java.util.*;
public class Dice {
static Scanner input = new Scanner(System.in);
public static void main(String[] args) {
final static int TIMES_TO_ROLL = getInt("Times to roll?");
Random flip = new Random();
int[] results = new int[TIMES_TO_ROLL];
for (int i = 0; i < TIMES_TO_ROLL; i++) {
int result = flip.nextInt(6);
System.out.println(result);
results[i] = result;
}
}
public static int getInt(String prompt) {
System.out.print(prompt + " ");
int integer = input.nextInt();
input.nextLine();
return integer;
}
}
So can someone help me with the array counting code? I understand that this might not be a defined method, since Python is higher level after all, so I could make my own array counting method, but I was wondering if Java, like Python, has a predefined one.
EDIT: I managed something like this:
public static int arrayCount(int[] array, int item) {
int amt = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] == item) {
amt++;
}
else {
amt = amt;
}
}
return amt;
}
EDIT: Just out of interest, assuming I use Command prompt to run my Java program and Python.exe (command prompt console for Python), which one will be faster (in other words, for the same code, which language has better performance?)?
You could use a HashMap to store the result.
If the new number is not in your map you add it with "1" as initial value.
If it exists your put "+1" to the current map value.
To display the values you just have to iterate on you entries in a for each loop.
The solution is to transform your array to a List and then use the Collections.frequency method:
List<Integer> resultList = Arrays.asList(results);
int freq = Collections.frequency(resultList, 4);
Also you could use ArrayList from the very beginning saving you the transformation:
List<Integer> result = new ArrayList<Integer>();
// add results
int freq = Collections.frequency(result, 4);
See the Collections documentation here
EDIT: If performance is an issue (as suggested in the comments) then maybe you want to use each index of the array as a counter, as follows:
Random flip = new Random(SIDES);
int[] counters = new int[SIDES];
for (int i = 0; i < TIMES_TO_ROLL; i++) {
int result = flip.nextInt;
counters[result] = counters[result]+1;
}
Notice that you no longer need to count at the end since you've already got all the counters in the array and there is no overhead of calculating the hash.
There are a couple libraries that will do this for you:
Google Guava's MultiSet
Apache Common's Bag
But for something so simple, you may consider an extra library a bit excessive.
You can also do this yourself with an int[]. Assuming your dice is using whole numbers, have the number rolled refer to the index into the array, and then increment the value at that index. When you need to retrieve the value for a given number, look up its value by the index.
private static final int NUMBER_DICE_SIDES = 6;
public static void main(String[] args) {
final static int TIMES_TO_ROLL = getInt("Times to roll?");
Random flip = new Random(NUMBER_DICE_SIDES);
int[] results = new int[NUMBER_DICE_SIDES];
for (int i = 0; i < TIMES_TO_ROLL; i++) {
int result = flip.nextInt;
System.out.println(result);
results[result]++;
}
for(int i = 0; i < NUMBER_DICE_SIDES; ++i) {
System.out.println((i+1)+"'s: " + arraysCount(results, i));
}
}
public static int arrayCount(int[] array, int item) {
return array[item];
}
There's a frequency method in collections
int occurrences = Collections.frequency(listObject, searchItem);
Java doc for collections
As far as I am aware, there is no defined method to return the frequency of a particular element in an array. If you were to write a custom method, it would simply be a matter of iterating through the array, checking each value, and if the value matches the element you're after, incrementing a counter.
So something like:
// in this example, we assume myArray is an array of ints
private int count( int[] myArray, int targetValue) {
int counter = 0;
for (int i = 0 ; i < myArray.length; i++ ) {
if (myArray[i] == targetValue) {
counter++;
}
}
return counter;
}
Of course, if you want to find the frequency of all the unique values in your array, this has the potential of being extremely inefficient.
Also, why are you using a 7-sided die? The Random nextInt() will return a number from 0 up to but not including the max. So your die will return values from 0 through 6. For a six-sided die, you'd want a new Random(6); and then increment your roll by one to get a value from one through six: flip.nextInt() +1;.
class FindOccurrence {
public static void main (String[]args) {
int myArray[] = {5, 8, 5, 12, 19, 5, 6, 7, 100, 5, 45, 6, 5, 5, 5};
int numToFind = 5;
int numberOfOccurrence = 0;
for (int i=0; i < myArray.length; i++) {
if (numToFind == myArray[i]) {
numberOfOccurrence++;
}
}
System.out.println("Our number: " + numToFind);
System.out.println("Number of times it appears: " + numberOfOccurrence);
}
}
My goal is to give the program a few items(Strings), a range, and target percent and let it give me all possible percentages of each item. For example, Imagine you go to the grocery store and have a basket of Apples & Pears you want to know all the percentages you could have using ALL items(not a full solution, I'm doing this by hand):
{Apple:50, Pears:50}, {Apple:75, Pears:25}, {Apple:90, Pears:10},etc.
If I do the same thing with a range of 20-50(meaning the highest value a single item can have is 50% and the lowest 20%) then the only result is:
{Apple:50, Pears:50} (since there are only 2 items and it cannot exceed 50% weight)
I thought it had similar traits as an knapsack problem with a few big differences since there are no values/weights associated with the items(but like knapsack problem trying to fit items in a knapsack I’m trying to fit values within a target_percent, 100%). I’m also having trouble applying general dynamic programming ideas as well since I can’t figure out how to break the problem down(typical knapsack problems build up results and then ‘cache’ results to reuse but if if I have a list of X items, I need all X items to be used within a range).
I can do this via brute force but I don’t feel like its efficient because it just tries everything so the bounds that I’m using aren’t being used to make it efficient at all(for example if apple is 75% then there’s no reason Pear should exceed 25%..bounds are size of list, range, and target_percent..I might have 20-30 list items with a range of 5-20 or maybe 50 items with a range from 1-5..or anything in between I want to play around with how many complete results I can get as fast as possible. I have not shown the target_percent part in the question because I can set it up that once I understand how to solve the problem, but basically all the examples assume 100% max, but sometimes you may already have 20% oranges in your basket and see how you can use Apples/Pears to fill up the rest 80%).
My questions are, How can I approach this(any ideas logic to use, examples or proxy problems I can look up)? Is dynamic programming appropriate for this problem or the fact that I cannot break this into smaller chucks a problem(remember because its always includes all items in the list, its not building up)? If someone can point me to the right direction, I’m willing to study any topics that might help(After spending 2 days trying to figure this out,I’m just not sure if the Dynamic programming route is correct). Also is there a name for this type of problem(I looked up knapsack problems, integer partitioning, combinatorics but none of them seemed to fit)?
Here's my(broken) brute force approach(its not actually working as expected but maybe gives you an idea of the brute force method):
import java.util.ArrayList;
import java.util.Arrays;
public class brute_force_percent_returner {
static String[] data = new String[]{"Apple", "Pears"};
static int[] coeff = new int[data.length];
static ArrayList<int[]> queue = new ArrayList<int[]>();
public static void main(String[] args) {
System.out.println("Starting");
recursion(0,data);
for (int[] item : queue) {
for (int item2 = 0; item2<data.length; item2++) {
System.out.print(data[item2] + " = " + item[item2] + " ");
}
System.out.println();
}
}
private static void recursion(int k, String[] data2) {
// this is not exactly working
for (String item: data2) {
for (int x = 0; x<5;x++) {
int[] coeff_temp = Arrays.copyOf(coeff, coeff.length);
coeff_temp[k] = x;
queue.add(coeff_temp);
}
}
if (k == data.length-1) {
return;
} else {
recursion(k+1, data2);
}
}
}
If it helps the solution I was trying to create was somewhat based on this one(its a knapsack problem but seems to be super quick for large number of variables but in this care the items its processing are the items in the list whereas in my case the list is just strings):
public class TurboAdder {
private static final int[] data = new int[] { 5, 10, 20, 25, 40, 50 };
private static class Node {
public final int index;
public final int count;
public final Node prevInList;
public final int prevSum;
public Node(int index, int count, Node prevInList, int prevSum) {
this.index = index;
this.count = count;
this.prevInList = prevInList;
this.prevSum = prevSum;
}
}
private static int target = 100;
private static Node sums[] = new Node[target+1];
// Only for use by printString.
private static boolean forbiddenValues[] = new boolean[data.length];
public static void printString(String prev, Node n) {
if (n == null) {
System.out.println(prev);
} else {
while (n != null) {
int idx = n.index;
// We prevent recursion on a value already seen.
if (!forbiddenValues[idx]) {
forbiddenValues[idx] = true;
printString((prev == null ? "" : (prev+" + "))+data[idx]+"*"+n.count, sums[n.prevSum]);
forbiddenValues[idx] = false;
}
n = n.prevInList;
}
}
}
public static void main(String[] args) {
for (int i = 0; i < data.length; i++) {
int value = data[i];
for (int count = 1, sum = value; count <= 100 && sum <= target; count++, sum += value) {
for (int newsum = sum+1; newsum <= target; newsum++) {
if (sums[newsum - sum] != null) {
sums[newsum] = new Node(i, count, sums[newsum], newsum - sum);
}
}
}
for (int count = 1, sum = value; count <= 100 && sum <= target; count++, sum += value) {
sums[sum] = new Node(i, count, sums[sum], 0);
}
}
printString(null, sums[target]);
}
}
This sounds like homework so I'm extra reluctant to help you too much, but here's an approach.
to define the ranges, make a couple hash maps, like
lower bounds = {apples => 20, pears => 40, oranges => 0}
upper bounds = {apples => 50, pears => 100, oranges => 30}
if you think about it, every final (valid) combination would at the very least, have the contents defined by the lower bound map. so call that the base combination.
next, figure out the theoretical max of each type you can potentially add to the base combination. this is just another map
{apples => 30, pears => 60, oranges => 30}
figure how many total items you can add to the base map, which is 100 - the sum of all the lower bound values, in the example its 40.
now, you need to generate the combinations. You'll probably find recursion the easiest way to do it. ill demonstrate the remaining algorithm with pseudo code and hardcoded stuff to improve clarity, although you'll need to write a generic, recursive version of it.
totalItemsToAdd = 40 //as calculated via baseCombo.sumOfEntries()
for (i=0; i<maxApples; i++) {
combo = clone the base combination
combo.apples += i;
remainingItemsToAdd = totalItemsToAdd - i;
if (remainingItemsToAdd > 0) {
for (j=0; j<maxPears; j++) {
combo.pears += j;
// and so on, recursively
}
}
results.append(combo)
}
notice how it only generates valid combinations by keeping track of how many more items are possible for each of the combinations. So, this wouldnt be brute force, and it would actually do the minimum work needed to generate the set of combinations.
I'm pretty confident that the brute-force approach is the best way to go - at least, that's the way I would do it (which is by no means the same thing...).
Here's an attempt to work with the recursive approach that I've got working (although I haven't tested it with high values for weightsNo. This works on the basis that you're interested in the combinations of weights, rather than the permutations of weights - although the switch is relatively straightforward.
public static Set<int[]> getPossiblePercentageWeights(int weightsNo, int min, int max){
return recusiveFixWeight(weightsNo, 100, min, max);
}
private static Set<int[]> recusiveFixWeight(int weightsNo, int sum, int min, int max){
Set<int[]> weightsSet = new LinkedHashSet<int[]>();
if (weightsNo>2){
for (int iWeight=min; iWeight<=max; iWeight++){
Set<int[]> subSet = recusiveFixWeight(weightsNo-1, sum-iWeight, min, iWeight);
for (int[] subWeights : subSet){
int[] weights = new int[weightsNo];
weights[0] = iWeight;
System.arraycopy(subWeights, 0, weights, 1, subWeights.length);
weightsSet.add(weights);
}
}
} else {
int iMax = Math.min(max, sum/weightsNo);
for (int iWeight=min; iWeight<=iMax; iWeight++){
int jWeight = sum-iWeight;
if (jWeight>=min && jWeight<=max){
weightsSet.add(new int[]{iWeight,jWeight});
}
}
}
return weightsSet;
}
That said, having looked at the results, it looks like there should be an algorithm to determine how many weightSets there given a weightsNo, min and max, and from there it should be fairly straightforward to fill those in with possible values. That said, I can't quite figure it out at the moment. (Or indeed, whether it would be any quicker than the brute-force approach...)