I'm struggling with a homework assignment and I believe I am vastly over-complicating the solution and need some help from anyone willing to offer it. Let me explain some ground rules for the assignment.
Below is a link to another post that has the exact problem informatation.
How do I solve the 'classic' knapsack algorithm recursively?
A set of numbers will be given such as for example: 15, 11, 8, 7, 6, 5. The first number always corresponds to the target or capacity of the knapsack. What I must do is recursively check all the numbers and see if any of the numbers add up to the capacity of the knapsack. If they do, I am to print the numbers that add up to the target sum and then continue checking for other possible solutions. When researching this problem, most posts solve for one solution. Let me explain the ground rules for the assignment.
This assignment must be done recursively, no exceptions.
All solutions must be found
The numbers are sorted from highest to lowest.
In the 15, 11, 8, 7, 6, 5 There was only one solution of 8 + 7 + 5 = 15. However, given a data set such as 15, 10, 9, 8, 7, 6, 5, 4, 3, 2 there exist multiple solutions such as.
10 + 5 = 15
9 + 6 = 15
8 + 7 = 15
Essentially there are two problems to solve.
From the previous post linked up above:
The idea, given the problem you stated (which specifies we must use recursion) is simple: for each item that you can take, see if it's better to take it or not. So there are only two possible path
you take the item
you don't take it
When you take the item, you remove it from your list and you decrease the capacity by the weight of the item.
When you don't take the item, you remove if from you list but you do not decrease the capacity.
I'm having some trouble getting my mind around what the author in this solution was saying.
For example: Assuming a number set of 20, 11, 8, 7, 6,5
1. Target is 20
2. Read in number from set: 11
4. 11 < 20, Add 11 to solution
5. New target is 9 (20 - 11)
6. Read in the next number: 8
7. 8 is less than 9, Add 8 to solution
8. New target is 1 (20 - 19)
9 Read in 7, 7 is larger than 1, do not add 7
What I'm failing to understand is what do I do if I don't add a number?
You take an item: You remove the item from your list and decrease the capacity
You dont take an item: You remove the item from your list but you don't decrease the capacity.
In my code, in either case of "take item" or "dont take item", I do not remove an item from my weight list and I think this is my problem to begin with.
I'll post some code I've worked on below for this assignment. As you can see, there is is an overly bloated solution that does not work as elegantly as the real solution should. If anyone could provide advice or insight on how to really solve this problem with the assignment parameters mentioned above, I would greatly appreciate it. Thank you.
import java.io.PrintWriter;
import java.util.ArrayList;
import javax.swing.JOptionPane;
public class Knapsack
{
public static void main(String[] args)
{
//Read in user input first
int[] tempArray;
String userInput = JOptionPane.showInputDialog("Enter a list of numbers delimited by a single space.");
String[] splitElements = userInput.split("\\s+");
//User array will contain the exact amount of
//numbers as long as extra spaces are not entered.
tempArray = new int[splitElements.length];
for(int i = 0; i < tempArray.length; i++)
{
tempArray[i] = Integer.parseInt(splitElements[i]);
}
Recursion recObj = new Recursion(tempArray);
}
}
class Recursion
{
private int[] weightArray;
private int [] solutionArray;
private int counter;
private int mainGoal;
private int [] backupOfOriginal;
private int solutionArrayCounter;
private ArrayList numberList;
private ArrayList previousSolutionsFound;
private int passThrough;
private int baseIterator;
private ArrayList distinctSolutions;
public Recursion(int[] paramArray)
{
weightArray = paramArray;
backupOfOriginal = weightArray;
solutionArray = new int[paramArray.length];
//Start at index 1 where the first number technically starts.
counter = 0;
//Keep track of main goal
mainGoal = weightArray[0];
solutionArrayCounter = 0;
passThrough = 0;
baseIterator = 0;
distinctSolutions = new ArrayList();
numberList = new ArrayList();
previousSolutionsFound = new ArrayList();
for(int i = 1; i < weightArray.length; i++)
{
numberList.add(weightArray[i]);
}
//Begin the recursive problem.
CheckForSums(mainGoal, numberList);
}
public void CheckForSums(int targetValue, ArrayList weightArray)
{
int numberRead = (Integer) weightArray.get(counter);
targetValue = ComputeTarget();
counter++;
//Base case if any number to read
//is greater than the main target value
//remove it
if(numberRead > mainGoal)
{
weightArray.remove(counter);
counter--;
}
if(numberRead <= targetValue)
{
AddToSolution(numberRead);
CheckForPossibleSolution();
//Add the item to the solution
}
//counter++;
if(counter == weightArray.size())
{
passThrough++;
counter = passThrough + 1;
RemoveOneFromSolution();
}
//Advance forward one position
if(passThrough == weightArray.size() - 1)
{
counter = 0;
passThrough = 0;
weightArray = RebuildArrayList(weightArray);
for(int i = 0; i < baseIterator; i++)
{
weightArray.remove(0);
}
baseIterator++;
ResetSolutionArray();
}
if(baseIterator == this.weightArray.length - 2)
{
//Should be completely done
return;
}
CheckForSums(targetValue, weightArray);
}
public void ResetSolutionArray()
{
solutionArrayCounter = 0;
for(int i = 0; i < solutionArray.length; i++)
{
solutionArray[i] = 0;
}
}
public void CheckForPossibleSolution()
{
if(SumOfSolutionsFound() == mainGoal)
{
PrintFoundSolution();
RemoveDownToBaseNumber();
}
else
{
System.out.println("No solution found yet.");
}
}
public void RemoveOneFromSolution()
{
if(solutionArrayCounter > 1)
{
solutionArrayCounter--;
}
if(solutionArrayCounter > 1)
{
solutionArray[solutionArrayCounter] = 0;
}
}
public void RemoveDownToBaseNumber()
{
while(solutionArrayCounter > 1)
{
solutionArrayCounter--;
solutionArray[solutionArrayCounter] =0;
}
}
public int SumOfSolutionsFound()
{
int sumOfSolutions = 0;
for(int i = 0; i < solutionArray.length; i++)
{
sumOfSolutions += solutionArray[i];
}
return sumOfSolutions;
}
public ArrayList<Integer> RebuildArrayList(ArrayList<Integer> paramList)
{
paramList = new ArrayList();
for(int i = 1; i < weightArray.length; i++)
{
paramList.add(weightArray[i]);
}
return paramList;
}
public void PrintFoundSolution()
{
StringBuilder toMessageBox = new StringBuilder();
System.out.print("Found a solution! ");
toMessageBox.append("Found a Solution! ");
for(int i = 0; i < solutionArray.length; i++)
{
System.out.print(solutionArray[i] + " ");
toMessageBox.append(solutionArray[i] + " ");
}
String finishedMessage = toMessageBox.toString();
boolean displayCurrentSolution = true;
for(int i = 0; i < previousSolutionsFound.size(); i++)
{
String previousSolution = previousSolutionsFound.get(i).toString();
if(finishedMessage.equals(previousSolution))
{
displayCurrentSolution = false;
}
}
previousSolutionsFound.add(finishedMessage);
if(displayCurrentSolution == true)
{
distinctSolutions.add(finishedMessage);
JOptionPane.showMessageDialog(null, finishedMessage,
"Solution for target: " + mainGoal, JOptionPane.INFORMATION_MESSAGE);
}
}
public void AddToSolution(int value)
{
solutionArray[solutionArrayCounter] = value;
solutionArrayCounter++;
}
public int ComputeTarget()
{
int sumOfSolutions = 0;
for(int i = 0; i < solutionArray.length; i++)
{
sumOfSolutions += solutionArray[i];
}
int numbersNeededToReachMainGoal = mainGoal - sumOfSolutions;
return numbersNeededToReachMainGoal;
}
}
The problem you described is actually a special case where you have only items weights, but no profits - or alternatively the weights and the profits are equal. This problem isusually not termed as Knapsack but the maximization version of Subset Sum.
Furthermore, for a recursive solution no array besides the input is needed.
Suppose the item sizes are given in the array weightArray (indices zero-based here) of length n and capacity denoted the total capacity availabel.
Define (first conceptually, not in code) the function
F( remainingCapacity, i ) :=
maximum total weight attainable for items
with indices in {0,..,i} of infinity if no such solution exists
note that
F( capacity, n - 1 )
yields the solution to the problem. Additionally, F has the property
F( remainingCapacity, -1 ) = 0 if remainingCapacity >= 0
and
F( remainingCapacity, i ) =
Infinity (can be simulated by a sufficiently
large integer) if remainingCapacity < 0
and
F( remainingCapacity, i ) =
max( F( remainingCapacity - weightArray[ i ], i - 1 ),
F( remainingCapacity, i - 1 ) )
where the first term in the maximum expression corresponds to the "take item i" case and the second expression corresponds to the "don't take item i" case. The cases above can more or less easily transformed to an actual implementation.
However note that this will yield only the maximum value attainable by a choice of items, but not the actual choice of items itself.
Related
The 7th number displayed separate. So in my opinion I can't put the 7 numbers in one array.
I want to print the 1st 6 in a line and the 7th number separate.
Can someone help?
The first 6 numbers are between 1 - 49 and sorted low-high and do not contain a duplicate.
The 7th number is no one of the first 6 but between 1 - 49 too.
I already generate a 7th number but sometimes it is a duplicate from one of the first 6.
This is the task :
Write a program that generates random numbers that I can enter on my next lottery ticket. When the program is started, it should generate 7 numbers. The first 6 are to be output in ascending order. The 7th number is the super number. It is issued separately. It is not sorted with .
import java.util.Arrays;
import java.util.Random;
public class RandomizedArrayExample
{
public static int[] zahlen = null;
public static void main(String[] args)
{
Random W = new Random();
try
{
zahlen = new int[6];
Random y = new Random();
int gesamt = 0;
boolean status = true;
while(status)
{
int zahl = y.nextInt(49)+1;
if(!isCompleted()){
if(!isDuplicate(zahl)){
zahlen[gesamt] = zahl;
gesamt++;
}else{
continue;
}
}else{
status = false;
}
}
} catch (Exception e) {
e.printStackTrace();
}
for(int q = 0; q<6-1; q++) {
for (int j = q+1; j<zahlen.length; j++) {
if(zahlen[q] > zahlen[j]) {
int k = zahlen[q];
zahlen[q] = zahlen[j];
zahlen[j] = k;
}
}
}
String ihreZahlen = "----Ersten 6 Zahlen----";
String superZahl = "-------Superzahl-------";
int x = W.nextInt(49)+1;
System.out.println(ihreZahlen);
System.out.println(Arrays.toString(zahlen));
System.out.println(superZahl);
}
public static boolean isCompleted(){
boolean status = true;
for (int i = 0; i < zahlen.length; i++){
if(zahlen[i]==0){
status = false;
break;
}
}
return status;
}
public static boolean isDuplicate(int num){
boolean status = false;
for (int i = 0; i < zahlen.length; i++){
if(zahlen[i]== num){
status = true;
break;
}
}
return status;
}
}
This is a sample output:
----Ersten 6 Zahlen----
[14, 16, 30, 38, 41, 45]
-------Superzahl-------
38
You see the 38 is a duplicate
When you do int x = W.nextInt(49)+1; you risk getting a duplicate as in your example output. Instead you need a loop where you again use isDuplicate() to check whether you got a duplicate and break out of the loop when you haven’t.
For a different and maybe batter solution there is nothing wrong with putting all 7 numbers in one array. You can always take them out from there into 6 numbers and 1 number. Here’s one way:
Random w = new Random();
int[] allNumbers = IntStream.generate(() -> w.nextInt(49) + 1)
.distinct()
.limit(7)
.toArray();
int[] numbers = Arrays.copyOf(allNumbers, 6);
Arrays.sort(numbers);
int superNumber = allNumbers[6];
String ihreZahlen = "----Ersten 6 Zahlen----";
String superZahl = "-------Superzahl-------";
System.out.println(ihreZahlen);
System.out.println(Arrays.toString(numbers));
System.out.println(superZahl);
System.out.println(superNumber);
Example output:
----Ersten 6 Zahlen----
[6, 8, 12, 16, 35, 42]
-------Superzahl-------
33
Here you assign x a value without checking if it's a duplicate:
int x = W.nextInt(49)+1;
add some logic to check if it is not already in your "zahlen array". The easiest way would be to add a while loop beneath it and use your isDuplicate method to check if it is already in your zahlen array. As long as this is the case you assign x new values.
int x;
do{
x = W.nextInt(49)+1;
}while(isDuplicate(x));
The longest increasing subsequence is the well known problem and I have a solution with the patience algorithm.
Problem is, my solution gives me the "Best longest increasing sequence" instead of the First longest increasing sequence that appears.
The difference is that some of the members of the sequence are larger numbers in the first(but the sequence length is exactly the same).
Getting the first sequence is turning out to be quite harder than expected, because having the best sequence doesn't easily translate into having the first sequence.
I've thought of doing my algorithm then finding the first sequence of length N, but not sure how to.
So, how would you find the First longest increasing subsequence from a sequence of random integers?
My code snippet:
public static void main (String[] args) throws java.lang.Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int inputInt;
int[] intArr;
try {
String input = br.readLine().trim();
inputInt = Integer.parseInt(input);
String inputArr = br.readLine().trim();
intArr = Arrays.stream(inputArr.split(" ")).mapToInt(Integer::parseInt).toArray();
} catch (NumberFormatException e) {
System.out.println("Could not parse integers.");
return;
}
if(inputInt != intArr.length) {
System.out.println("Invalid number of arguments.");
return;
}
ArrayList<ArrayList<Integer>> sequences = new ArrayList<ArrayList<Integer>>();
int sequenceCount = 1;
sequences.add(new ArrayList<Integer>());
sequences.get(0).add(0);
for(int i = 1; i < intArr.length; i++) {
for(int j = 0; j < sequenceCount; j++) {
if(intArr[i] <= intArr[sequences.get(j).get(sequences.get(j).size() - 1)]) {
sequences.get(j).remove(sequences.get(j).size() - 1);
sequences.get(j).add(i);
break;
} else if (j + 1 == sequenceCount) {
sequences.add(new ArrayList<Integer>(sequences.get(j)));
sequences.get(j + 1).add(i);
sequenceCount++;
break; //increasing sequenceCount causes infinite loop
} else if(intArr[i] < intArr[sequences.get(j + 1).get(sequences.get(j + 1).size() - 1)]) {
sequences.set(j+ 1, new ArrayList<Integer>(sequences.get(j)));
sequences.get(j+ 1).add(i);
break;
}
}
}
int bestSequenceLength = sequenceCount;
ArrayList<Integer> bestIndexes = new ArrayList<Integer>(sequences.get(bestSequenceLength - 1));
//build bestSequence, then after it I'm supposed to find the first one instead
int[] bestSequence = Arrays.stream(bestIndexes.toArray()).mapToInt(x -> intArr[(int) x]).toArray();
StringBuilder output = new StringBuilder("");
for(Integer x : bestSequence) {
output.append(x + " ");
}
System.out.println(output.toString().trim());
}
I'm storing indexes instead in preparation for having to access the original array again. Since it's easier to go from indexes to values than vice versa.
Example:
3 6 1 2 8
My code returns: 1 2 8
First sequence is: 3 6 8
Another Example:
1 5 2 3
My code correctly returns: 1 2 3
Basically, my code works as long as the first longest sequence is the same as the best longest sequence. But when you have a bunch of longest sequences of the same length, it grabs the best one not the first one.
Code is self-explanatory. (Have added comments, let me know if you need something extra).
public class Solution {
public static void main(String[] args) {
int[] arr = {3,6,1,2,8};
System.out.println(solve(arr).toString());
}
private static List<Integer> solve(int[] arr){
int[][] data = new int[arr.length][2];
int max_length = 0;
// first location for previous element index (for backtracing to print list) and second for longest series length for the element
for(int i=0;i<arr.length;++i){
data[i][0] = -1; //none should point to anything at first
data[i][1] = 1;
for(int j=i-1;j>=0;--j){
if(arr[i] > arr[j]){
if(data[i][1] <= data[j][1] + 1){ // <= instead of < because we are aiming for the first longest sequence
data[i][1] = data[j][1] + 1;
data[i][0] = j;
}
}
}
max_length = Math.max(max_length,data[i][1]);
}
List<Integer> ans = new ArrayList<>();
for(int i=0;i<arr.length;++i){
if(data[i][1] == max_length){
int curr = i;
while(curr != -1){
ans.add(arr[curr]);
curr = data[curr][0];
}
break;
}
}
Collections.reverse(ans);// since there were added in reverse order in the above while loop
return ans;
}
}
Output:
[3, 6, 8]
I have a homework task as follows:
The bin packing problem is to pack the objects of
various weights into containers. Assume each
container can hold a maximum of 10 pounds. The
program uses an algorithm that places an object into
the first bin in which it would fit. Your program should
prompt the user to enter the total number of objects
and the weight of each object. The program displays
the total number of containers needed to pack the
objects and the content of each container. Here is a
simple run of the program:
Enter the number of objects: 6
Enter the weight of the objects: 7 5 2 3 5 8
Container 1 contains objects with weight: 7 2
Container 2 contains objects with weight: 5 3
Container 3 contains objects with weight: 5
Container 4 contains objects with weight: 8
Now I have decided to try making it smarter and optimize the object allocation. It seemed to be working fine, but when I started testing using more numbers than the sample run I noticed that the highest I can go is 27 objects. Anything higher and I start getting a few containers at the end of the execution that could be merged into a single one. Any ideas and suggestions are welcome. Thank you in advance!
package classwork;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
import java.util.Scanner;
public class BinPacking {
private static final int binLimit = 10;
public static boolean lessThanLimit(int a, int b) {
if (a + b < binLimit) {
return true;
} else {
return false;
}
}
public static boolean perfectFit(int a, int b) {
if (a + b == binLimit) {
return true;
} else {
return false;
}
}
public static boolean weightsLeft(boolean[] a) { // check if there is one more item that has not been binned yet.
for (boolean b : a) {
if (b) {
return true;
}
}
return false;
}
public static ArrayList<int[]> distributeObjects(int[] weights) {
int counter = 0;
boolean[] objectAssigned = new boolean[weights.length]; // array to track which objects have been assigned already
ArrayList<int[]> result = new ArrayList<int[]>(); // list of int[] to be returned
for (int i = 0; i < weights.length; i++) {
ArrayList<Integer> currentBin = new ArrayList<Integer>(); // list to store the values of the weights in currrent bin
int currentBinWeight = 6;
if (!objectAssigned[i]) {
currentBin.add(weights[i]);
currentBinWeight = weights[i];
objectAssigned[i] = true;
} else
counter = 1;
stupidLoopThatWontBreak:
while (currentBinWeight < binLimit && counter < 1) {
counter = 1;
if (!weightsLeft(objectAssigned)) { // break loop if no more weights left
result.add(currentBin.stream().mapToInt(Integer::intValue).toArray());
break stupidLoopThatWontBreak;
}
for (int j = i + 1; j < weights.length; j++) {
if (perfectFit(currentBinWeight, weights[j]) && !objectAssigned[j]) {
currentBin.add(weights[j]);
currentBinWeight += weights[j];
objectAssigned[j] = true;
break stupidLoopThatWontBreak;
}
if (lessThanLimit(currentBinWeight, weights[j]) && !objectAssigned[j]) {
currentBinWeight += weights[j];
currentBin.add(weights[j]);
objectAssigned[j] = true;
}
}
}
// convert arraylist to int[] and add it to result. Java 8+ feature
if (!currentBin.isEmpty()) {
result.add(currentBin.stream().mapToInt(Integer::intValue).toArray());
counter = 0;
}
}
return result;
}
public static void main(String[] args) {
System.err.println("Container weight limit is " + binLimit);
Scanner in = new Scanner(System.in);
//Test numbers 7, 5, 3, 2, 5, 8
// System.out.print("Enter the weights of the objects you want to put into the bins: ");
// String input = in.nextLine();
// in.close();
//========================Random numbers for testing======================
String input = "";
Random ran = new Random();
System.out.print("Enter number of weights to be randomly generated: ");
int num = in.nextInt();
in.close();
for (int i = 0; i < num; i++) {
input += (ran.nextInt(binLimit) + 1) + " "; //+1 to not have zeroes
}
//========================End of random numbers===========================
ArrayList<Integer> list = new ArrayList<Integer>();
String[] str = input.trim().split(" "); // trim surrounding spaces, use space char as separator
for (String a : str) {
list.add(Integer.valueOf(a));
}
// sort the list in a descending order
Collections.sort(list);
Collections.reverse(list); // this could be avoided if I started checking from the last index in distributeObjects()
System.out.println("The generated and sorted descendingly weights are:");
System.out.println("\n" + list.toString() + "\n");
int[] weights = new int[list.size()];
for (int a = 0; a < weights.length; a++) {
weights[a] = list.get(a);
}
ArrayList<int[]> bins = distributeObjects(weights);
for (int i = 0; i < bins.size(); i++) {
System.out.println("Container " + (i + 1) + " contains objects with weight: " + Arrays.toString(bins.get(i)));
}
}
}
Since I cannot comment, I am posing this as an answer -
Run above code with "10 9 8 8 8 7 7 7 6 6 6 5 5 5 4 4 4 4 4 3 3 2 2 2 2 2 2 2 1 1" as input array and you will see the problem being caused by 'counter' variable. If you replace 'counter=1;' from else with 'continue;' it should work for this input. You still need to test this for other inputs. Also, the above code needs refactoring - for example - use either list or weights. Both are nor required.
I tried not to distort your code too much, but this should give you your desired output. The problem was with your second loop, it caused some trouble with the counter variable since counter was never set back to 0 at the end of your loop if the bin should not already be added (when you did not find the first weight that has to be added to the bin).
The easiest way to fix your program is simply to move counter = 0; inside the if statement where you check if there is already a weight inside of the bin or not outside of the if block.
I removed the "stupidLoopThatWouldNotBreak" below and replaced it with another for loop, that looks through all remaining weights if there is one that can fit.
public static ArrayList<int[]> distributeObjects(int[] weights) {
boolean[] objectAssigned = new boolean[weights.length]; // array to track which objects have been assigned already
ArrayList<int[]> result = new ArrayList<int[]>(); // list of int[] to be returned
for (int i = 0; i < weights.length; i++) {
ArrayList<Integer> currentBin = new ArrayList<Integer>(); // list to store the values of the weights in currrent bin
int currentBinWeight = 0;
//This loop searches for the first unused Weight, so you do not need `count` anymore
for (int j = i; j < weights.length; j++) {
if (!objectAssigned[j]) {
currentBin.add(weights[j]);
currentBinWeight = weights[j];
objectAssigned[j] = true;
break;
}
i = j; //You can skip all iterations with used weights
}
for (int j = i; j < weights.length && currentBinWeight < binLimit; j++) {
if (perfectFit(currentBinWeight, weights[j]) && !objectAssigned[j]) {
currentBin.add(weights[j]);
currentBinWeight += weights[j];
objectAssigned[j] = true;
break; //this break gives some performance bonus
}
if (lessThanLimit(currentBinWeight, weights[j]) && !objectAssigned[j]) {
currentBinWeight += weights[j];
currentBin.add(weights[j]);
objectAssigned[j] = true;
}
}
// convert arraylist to int[] and add it to result. Java 8+ feature
if (!currentBin.isEmpty()) {
result.add(currentBin.stream().mapToInt(Integer::intValue).toArray());
}
}
return result;
}
You can further enhance your code if you split this loop up. You can add more functions like the two helperfunctions perfectFit and lessThanlimit. You can for example add another function that will search for the first empty element, maybe even add it to the bin. Also the 2 functions you already have could be merged into one function called addWeight or attemptAdd. Furthermore you could create seperate classes for the bin and for the weights.
How can i get value value 11 and 15 because there is a missing values 12,13,14.I have got snippet from this SO post:
I could not use it for array with no fixed size.
int binaryValue[] = null;
ArrayList<Integer> al;
Vector father = new Vector();
Vector child;
int start = al.get(0);
for(int i = 0; i < al.size(); i++) {
if(al.get(i) != i + start) {
child = new Vector();
child.add(al.get(i-1));
child.add(al.get(i));
father.add(child);
}
}
Child should have 11 and 15 and so on ....
This is pure logic based issue, you just need to look for next element to find the gap, see below working sample:
public class GapFinder {
private static int[] myIntArr = {9, 10, 11, 12, 13, 15};
public static void main(String[] args) {
int a = 0,b = 0;
for (int i = 0; i < myIntArr.length; i++) {
if(((i + 1) < myIntArr.length) && myIntArr[i] != myIntArr[i + 1] - 1) {
a = myIntArr[i];
b = myIntArr[i + 1];
break;
}
}
if(a == 0 && b == 0){
System.out.println("There were no gaps.");
} else{
System.out.println("Gaps: " + a + " | " + b);
}
}
}
Please note:
This is not a concept which I could possibly explain, this is pure logic and I have said this in my opening statement, and logic is also straight forward which needs no explaination, its quiet implicit and not a complex algorithmic logic; OP just needed to loop for next element to identify the gap, until next/previous element is checked, a gap cannot be identified with getting expected values, this was just a small step OP was missing and OP got it
This is a working solution, there could be corner cases like what #9000 mentioned in his comment, it is basic assumption that I cannot provide answer handling all corner cases, I am just highlighting the logic which would help solve the problem.
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);
}
}