I've got a method that is meant to work out the group of elements of a 3D array with the highest combined value. I've got 3 nested loops that I'm using to go through my array, and as certain conditions are met I want to alter the variables. However none of the variables are being used. I ant to alter int y and int m to whatever iteration of the for loop it's on if sum exceeds total.
Thanks. Here is my code:
public void wettestMonth(){
double sum = 0;
double total = 0;
int y = 0;
int m = 0;
//cycle through each year and month
for(int i = 0; i < 34; i++){
for(int j = 0; j < 12; j++){
//reset the current month to 0 after each month has been cycled through
sum = 0;
for(int k = 0; k < 31; k++){
//only add the record if the current entry is not null (-99.99)
if(sortedData[i][j][k] != -99.99){
sum += sortedData[i][j][k];
}
//if the current month is wetter than the wettest one, make the current month the new wettest one
if(sum > total){
total = sum;
y = i;
m = j;
}
}
}
}
JOptionPane.showMessageDialog(null, "The wettest month on record was " +m +y, "Wettest Month.", JOptionPane.PLAIN_MESSAGE);
}
Edit, I just reconstructed it with while loops instead and I'm getting an out-of-bounds error on what appears to be the problem line, if(sortedData[i][j][k] != -99.99)
Edit 2, here is where I declare and initialise sortedData[][][]
public class GetData {
//initialises an array that holds 34 years, each with 12 months, each of which has 31 entries for reach day
public double[][][] sortedData = new double[34][12][31];
//initialises a new scanner named rainFile
private Scanner rainFile;
//method for opening the file
public void openFile() {
try{
//as the input for the scanner we use the rainfall file
rainFile = new Scanner(new File("C:\\\\Users\\\\admin\\\\Documents\\\\NetBeansProjects\\\\110_term3\\\\WeatherDataFiles\\\\rainfall.txt"));
}
catch(Exception e){
//if no file has been found a JOptionPane will display an error message telling the user to double-check the file path
JOptionPane.showMessageDialog(null, "Check the file path is correct.", "No file found!", JOptionPane.ERROR_MESSAGE);
}
}
//method for reading the file
public void readFile(){
//ignore the first 3 lines in the data file
String dump1 = rainFile.nextLine();
String dump2 = rainFile.nextLine();
String dump3 = rainFile.nextLine();
//these nested for loops will dictate the current index of sortedData
for(int i = 0; i < 34; i++){
for(int j = 0; j < 12; j++){
//ignores the year and month at the start of each line
String dump4 = rainFile.next();
String dump5 = rainFile.next();
//this final nested for loop dictates the final index of sortedData
for(int k = 0; k < 31; k++){
//asigns the current value of scanner rainFile to String a
String a = rainFile.next();
//converts the String a to a double type and then assigns it to the current index of sortedData
double dbl = Double.parseDouble(a);
sortedData[i][j][k] = dbl;
}
}
}
}
Have you tried printing out the sum for each month?
The most obvious possibility is that your sums are always less than 0 because of a buggy equality check.
For this line,
sortedData[i][j][k] != -99.99
It will be true unless the value is exactly what -99.99 rounds to. This may be unintended. For example, if you are constructing the value through floating point math somehow, you most likely won't get exactly the same value due to rounding errors. Furthermore, use of a weird sentinel value like this is error prone and less readable. You're better off using an obvious sentinel value like NaN if you can.
To see the problem, consider what would happen if your values are slightly different. Say, -99.99000001. Then after the first day, you already have a negative value. After a month, the sum will be approximately -3099.69000031, much less than 0. Since the sum is always negative, it is never better than the original total 0, so the best never gets updated.
You probably also want to move the update check outside of the day loop. This part looks like it's supposed to use the sum for the whole month, but you are running it with the partial sum of every day of the month. It won't actually cause incorrect results as long as the values being added are nonnegative (but they probably aren't due to the aforementioned bug), but you should still fix it.
if(sum > total){
total = sum;
y = i;
m = j;
}
I don't see anything wrong on your code.
Maybe the following condition never evals to true?
if(sortedData[i][j][k] != -99.99)
Carefully, reviewed the first code snippet that has been provided, it appears to me that you have been doing if check for the size inside the for loop, moved the for loop vars to the finals, added some further comments.
You could try and run your swing app through the Eclipse debug and see what results you get at each line in your application ?
Would expect it to work given correct input 3D array))
/**
* This method calculates the wettest month during the certain period of time.
*/
public void wettestMonth(){
double sum = 0;
double total = 0;
int y = 0;
int m = 0;
final int numberOfYearsToCycleThrough = 34;
final int numberOfMonthsToCycleThrough = 12;
//cycle through each year and month
for (int i = 0; i < numberOfYearsToCycleThrough; i++) {
for (int j = 0; j < numberOfMonthsToCycleThrough; j++) {
sum = 0;
for (int k = 0; k < 31; k++){
//only add the record if the current entry is not null (-99.99)
if (sortedData[i][j][k] != null && sortedData[i][j][k] != -99.99) {
sum += sortedData[i][j][k];
}
}
//if the current month is wetter than the wettest one, make the current month the new wettest one
if (sum > total) {
total = sum;
y = i;
m = j;
}
}
}
JOptionPane.showMessageDialog(null, "The wettest month on record was " +m +y, "Wettest Month.", JOptionPane.PLAIN_MESSAGE);
}
Related
I had an online coding test where the problem was described as below. I could not finish the question but did leave some comments on how to come up with a potential solution. I wanted to know what have been the best to solve this problem. The main issue I was having was splitting the given inputs as string and finding a suitable collection to put them in. Below is the question.
You want to send your friend a package with different things.
Each thing you put inside of a package has such parameters as index number, weight and cost.
The package has a weight limitation.
Your goal is to determine which things to put into the package so that the total weight is less than or equal to the package limit and the total cost is as large as possible.
You would prefer to send a package which has less weight if there is more than one package with the same price.
This is a variation of the Knapsack problem.
Input:
Your program should read lines from standard input. Each line contains the weight that a package can take (before the colon) and the list of things you need to pick from. Each thing is enclosed in parentheses where the 1st number is a thing's index number, the 2nd is its weight and the 3rd is its cost.
Max weight any package can take is <= 100.
There might be up to 15 things you need to choose from.
Max weight and max cost of any thing is <= 100.
Output:
For each set of things produce a list of things (their index numbers separated by comma) that you put into the package. If none of the items will fit in the package, print a hyphen (-).
Test 1
Input81 : (1,53.38,$45) (2,88.62,$98) (3,78.48,$3) (4,72.30,$76) (5,30.18,$9) (6,46.34,$48)
Expected Output 4
Test 2
Test Input 75 : (1,85.31,$29) (2,14.55,$74) (3,3.98,$16) (4,26.24,$55) (5,63.69,$52) (6,76.25,$75) (7,60.02,$74) (8,93.18,$35) (9,89.95,$78)
Expected Output 2,7
There might be up to 15 things you need to choose from. so you have possible combination 2^15 = 32,768. So you can
check every combination and find out which combination meet requirement.
Exampe: there is 3 (1,2,3) things.
then u can choose: (),(1),(2),(3),(1,2),(1,3),(2,3),(1,2,3).
Now need tho find which combination meet requirements.
Here is solution:
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s = in.nextLine();
String res[] = s.replaceAll("[^0-9.]+",";").split(";");
double target = Integer.parseInt(res[0]);
int n = (res.length-1) / 3;
int[] Index = new int[20];
double[] P = new double[20];
double[] W = new double[20];
int jj = 0;
for(int i = 1; i < res.length; i +=3){
Index[jj] = Integer.parseInt(res[i]);
W[jj] = Double.parseDouble(res[i+1]);
P[jj++] = Double.parseDouble(res[i+2]);
}
double result = 0;
int track = 0;
double resSum = 0;
for(int i =0; i< (1<<n); i++){
double sum = 0;
double weight = 0;
for(int j=0; j < n; j++){
if(((1<<j)&i) > 0){
sum+= P[j];
weight+=W[j];
}
}
if(weight <= target){
if(sum > resSum){
result = weight;
track = i;
resSum = sum;
}else if(sum == resSum && weight < result){
result = weight;
track = i;
}
}
}
jj = 0;
for(int i = 0; i < n; i++){
if(((1<<i)&track) > 0){
if(jj > 0){
System.out.print(",");
}
jj = 1;
System.out.print(Index[i]);
}
}
if(track == 0){
System.out.println("-");
}else {
System.out.println();
}
}
My code calculates the population deviation when I need it to calculate the sample deviation I have compared both formulas and tried changed my calculations but nothing seems to work. Thanks for everyone's help or input in advance.
public class MeanAndStandardDeviation {
public static void main (String argv []) throws IOException {
BufferedReader stdin =
new BufferedReader (new InputStreamReader (System.in));
NumberFormat nf = new DecimalFormat ("0.00");
nf.setMinimumFractionDigits (2);//Sets Min digits
nf.setMaximumFractionDigits (2);//Sets Max digits
String inputValue;
int count = 0;
//For Loop for count
for(int i = 0; i < count; i++){
count++;
}
double varianceFinal = 0;
List<String> input = new ArrayList<String>();//String ArrayList
List<Double> numbers = new ArrayList<Double>();//Double ArrayList
//While loop that takes in all my input and assigns it to the ArrayLists
//Parameters set for when null is entered and total numbers go over 500
while((inputValue = stdin.readLine()) != null && !inputValue.equals("") && input.size()<500){//Parameters set for when null is entered and total numbers go over 500
input.add(inputValue);
numbers.add (Double.parseDouble(inputValue));
}
System.out.println ("Standard Deviation: " +(nf.format(calcStdDev (numbers, count, varianceFinal))));//Prints the Standard Deviation
}
//StandardDeviation Class
static double calcStdDev (List<Double> numbers, int count, double variance){
variance = 0;
double sum = 0;
for(int i = 0; i < numbers.size(); i++){
sum += numbers.get(i);
variance += numbers.get(i) * numbers.get(i);
count++;
}
double varianceFinal = ((variance/count)-(sum*sum)/(count*count));
return Math.sqrt(varianceFinal);
}
}
Seriously, your code is "wrong" on many levels. So instead of debugging all of that for you, I will give you some hints how to fix and simplify your code - then it should be very easy for you to fix/resolve your actual math problem.
First of all, your code is so written in a confusing style that just makes it much harder to understand (and therefore debug) than it needs to be.
Example:
int count = 0;
//For Loop for count
for(int i = 0; i < count; i++){
count++;
}
That for loop doesn't do anything. And even when the condition would be something else, like i < someNumber; you would still just need to put count = someNumber there; instead of looping!
Same here: what is the point of providing count as argument to your calc methods?! And to then just increase it? So, lets rewrite that:
public static double calcStdDev (List<Double> numbers, double variance) {
double sumOfNumbers = 0;
double sumOfSquares = 0;
for(double number : numbers) {
sumOfNumbers += number;
sumOfSquares += number * number;
}
... and instead of calculating count, you simply have
int numberOfNumbers = numbers.size();
... and now, do your math
The other thing that is really strange in your code is how you setup your variance variable; and how it is used within your calc methods.
Long story short: step back and remove everything from your code that isn't required.
It is a bad idea to compute the variance as you do. If the mean is largeish, eg 10 million, and the noise is smallish, eg around 1 then the limited precision of doubles may well mean that your computed variance is negative and the the sd will be nan.
You should either compute it in two passes, eg
double mean = 0.0;
for( i=0; i<n; ++i)
{ mean += x[i];
}
mean /= n;
double var = 0.0;
for( i=0; i<n; ++i)
{
double d = x[i] - mean;
var += d*d;
}
var /= n;
or in one pass, eg
double mean = 0.0;
double var = 0.0;
for( i=0; i<n; ++i)
{
double f = 1.0/(i+1);
double d = x[i]-mean;
mean += d*f;
var = (1.0-f)*(var + f*d*d);
}
(it takes a bit of tedious algebra to show that the one pass method gives the same answer as the two pass method).
The line birthdays[j] = rnd.nextInt(365); seems to generate extra 0's in the int[] birthdays array. It also seems to add an EXTRA 0 into the array and generate static values depending on how many simulations I run and how many birthdays I generate. For instance, if I do 5 simulations and enter a 3 for the number of people in each simulation's "birthday pool" I always get an array of [0, 0, 289, 362].
Any help understanding the problem would be greatly appreciated.
public static void main(String[] args) {
System.out.println("Welcome to the birthday problem Simulator\n");
String userAnswer="";
Scanner stdIn = new Scanner(System.in);
do {
int [] userInput = promptAndRead(stdIn);
double probability = compute(userInput[0], userInput[1]);
// Print results
System.out.println("For a group of " + userInput[1] + " people, the probability");
System.out.print("that two people have the same birthday is\n");
System.out.println(probability);
System.out.print("\nDo you want to run another set of simulations(y/n)? :");
//eat or skip empty line
stdIn.nextLine();
userAnswer = stdIn.nextLine();
} while (userAnswer.equals("y"));
System.out.println("Goodbye!");
stdIn.close();
}
// Prompt user to provide the number of simulations and number of people and return them as an array
public static int[] promptAndRead(Scanner stdIn) {
int numberOfSimulations = 0;
while(numberOfSimulations < 1 || numberOfSimulations > 50000) {
System.out.println("Please Enter the number of simulations to do. (1 - 50000) ");
numberOfSimulations = stdIn.nextInt();
}
int sizeOfGroup = 0;
while(sizeOfGroup < 2 || sizeOfGroup > 365) {
System.out.println("Please Enter the size of the group of people. (2 - 365) ");
sizeOfGroup = stdIn.nextInt();
}
int[] simulationVariables = {numberOfSimulations, sizeOfGroup};
return simulationVariables;
}
// This is the method that actually does the calculations.
public static double compute(int numOfSims, int numOfPeeps) {
double numberOfSims = 0.0;
double simsWithCollisions = 0.0;
int matchingBirthdays = 0;
int[] birthdays = new int[numOfPeeps + 1];
int randomSeed = 0;
for(int i = 0; i < numOfSims; i++)
{
randomSeed++;
Random rnd = new Random(randomSeed);
birthdays = new int[numOfPeeps + 1];
matchingBirthdays = 0;
for(int j = 0; j < numOfPeeps; j++) {
birthdays[j] = rnd.nextInt(365);
Arrays.sort(birthdays);
}
for(int k = 0; k < numOfPeeps; k++) {
if(birthdays[k] == birthdays[k+1]) {
matchingBirthdays++;
}
}
if(matchingBirthdays > 0) {
simsWithCollisions = simsWithCollisions + 1;
}
}
numberOfSims = numOfSims;
double chance = (simsWithCollisions / numberOfSims);
return chance;
}
}
The line "birthdays[j] = rnd.nextInt(365);" seems to generate extra 0's in the int[] birthdays array.
Well, it doesn't. The array elements where zero to start with.
What that statement actually does is to generate a single random number (from 0 to 364) and assign it to one element of the array; i.e. the jth element. That is not what is required for your problem.
Now, we could fix your code for you, but that defeats the purpose of your homework. Instead I will give you a HINT:
The birthdays array is supposed to contain a COUNT of the number of people with a birthday on each day of the year. You have to COUNT them. One at a time.
Think about it ...
int arrays are by default initialized to 0 unless explicitly specified. Please see this Oracle tutorial about Arrays.
I found the problem myself. The issue was that having the "Arrays.sort(birthdays);" statement inside of a loop. That generated extra 0's.
trying to further my comprehension of loops and I found some questions online that I'm trying to complete but I got stuck on the second last one.
The original question was :
loop4(int val). This method uses a loop (for or while?) to do the following. Generate a random number between 1 and 10 (including 1 and 10) 10 times and count how many times val is generated, then print that number out.
What I've managed to do so far:
public int Loop4(int val){
for(int i = Math.random()*10; i<= 10; val!=0){
if (i == val) {
System.out.println(//I cannot for the life of me think of how I could constantly increment a +1 to this value because I only want to end up with 1 number in the end)
}
}
}
Simply create an count value and increment it.
public int Loop4(int val){
int count = 0;
for(int i = 0; i< 10; i++){
if ((int)(Math.random()*10) == val) {
count++;
}
}
System.out.println(count);
return count;
}
This code will do the trick:)
public int Loop4(int val){
int totalCount = 0;
for(int i = 0; i<= 10; i++){
int generatedNumber = (int)(Math.random()*10);
if (generatedNumber == val){
totalCount++;
}
}
System.out.print(totalCount );
}
You may want to try something like this. From your question you only want to loop 10 times and count how many times val is generated. You should create a total variable and increment each time the new random number == val.
Ex:
public int Loop4(int val){
int total = 0;
for(int i = 0; i <= 10; i++){
if ((int)(Math.random()*10) == val) {
total++;
}
}
return total;
}
There are a couple things in your code that you need to consider.
First, Math.random() returns a double, not an int so you have to cast it: (int) Math.random() (However casting this will cause some issue with rounding so do some research on that).
Second, the third argument in a for loop needs to be an iteration, not a comparison.
Ex: i++, ++i, --i
Third, create another variable int count = 0 that will count the number of times a number appears and place: count++ inside of your inner if statement and then have the System.out print it after your iteration.
this is the question, and yes it is homework, so I don't necessarily want anyone to "do it" for me; I just need suggestions: Maximum sum: Design a linear algorithm that finds a contiguous subsequence of at most M in a sequence of N long integers that has the highest sum among all such subsequences. Implement your algorithm, and confirm that the order of growth of its running time is linear.
I think that the best way to design this program would be to use nested for loops, but because the algorithm must be linear, I cannot do that. So, I decided to approach the problem by making separate for loops (instead of nested ones).
However, I'm really not sure where to start. The values will range from -99 to 99 (as per the range of my random number generating program).
This is what I have so far (not much):
public class MaxSum {
public static void main(String[] args){
int M = Integer.parseInt(args[0]);
int N = StdIn.readInt();
long[] a = new long[N];
for (int i = 0; i < N; i++) {
a[i] = StdIn.readLong();}}}
if M were a constant, this wouldn't be so difficult. For example, if M==3:
public class MaxSum2 {
public static void main(String[] args){
int N = StdIn.readInt(); //read size for array
long[] a = new long[N]; //create array of size N
for (int i = 0; i < N; i++) { //go through values of array
a[i] = StdIn.readLong();} //read in values and assign them to
//array indices
long p = a[0] + a[1] + a[2]; //start off with first 3 indices
for (int i =0; i<N-4; i++)
{if ((a[i]+a[i+1]+a[1+2])>=p) {p=(a[i]+a[i+1]+a[1+2]);}}
//if sum of values is greater than p, p becomes that sum
for (int i =0; i<N-4; i++) //prints the subsequence that equals p
{if ((a[i]+a[i+1]+a[1+2])==p) {StdOut.println((a[i]+a[i+1]+a[1+2]));}}}}
If I must, I think MaxSum2 will be acceptable for my lab report (sadly, they don't expect much). However, I'd really like to make a general program, one that takes into consideration the possibility that, say, there could be only one positive value for the array, meaning that adding the others to it would only reduce it's value; Or if M were to equal 5, but the highest sum is a subsequence of the length 3, then I would want it to print that smaller subsequence that has the actual maximum sum.
I also think as a novice programmer, this is something I Should learn to do. Oh and although it will probably be acceptable, I don't think I'm supposed to use stacks or queues because we haven't actually covered that in class yet.
Here is my version, adapted from Petar Minchev's code and with an important addition that allows this program to work for an array of numbers with all negative values.
public class MaxSum4 {
public static void main(String[] args)
{Stopwatch banana = new Stopwatch(); //stopwatch object for runtime data.
long sum = 0;
int currentStart = 0;
long bestSum = 0;
int bestStart = 0;
int bestEnd = 0;
int M = Integer.parseInt(args[0]); // read in highest possible length of
//subsequence from command line argument.
int N = StdIn.readInt(); //read in length of array
long[] a = new long[N];
for (int i = 0; i < N; i++) {//read in values from standard input
a[i] = StdIn.readLong();}//and assign those values to array
long negBuff = a[0];
for (int i = 0; i < N; i++) { //go through values of array to find
//largest sum (bestSum)
sum += a[i]; //and updates values. note bestSum, bestStart,
// and bestEnd updated
if (sum > bestSum) { //only when sum>bestSum
bestSum = sum;
bestStart = currentStart;
bestEnd = i; }
if (sum < 0) { //in case sum<0, skip to next iteration, reseting sum=0
sum = 0; //and update currentStart
currentStart = i + 1;
continue; }
if (i - currentStart + 1 == M) { //checks if sequence length becomes equal
//to M.
do { //updates sum and currentStart
sum -= a[currentStart];
currentStart++;
} while ((sum < 0 || a[currentStart] < 0) && (currentStart <= i));
//if sum or a[currentStart]
} //is less than 0 and currentStart<=i,
} //update sum and currentStart again
if(bestSum==0){ //checks to see if bestSum==0, which is the case if
//all values are negative
for (int i=0;i<N;i++){ //goes through values of array
//to find largest value
if (a[i] >= negBuff) {negBuff=a[i];
bestSum=negBuff; bestStart=i; bestEnd=i;}}}
//updates bestSum, bestStart, and bestEnd
StdOut.print("best subsequence is from
a[" + bestStart + "] to a[" + bestEnd + "]: ");
for (int i = bestStart; i<=bestEnd; i++)
{
StdOut.print(a[i]+ " "); //prints sequence
}
StdOut.println();
StdOut.println(banana.elapsedTime());}}//prints elapsed time
also, did this little trace for Petar's code:
trace for a small array
M=2
array: length 5
index value
0 -2
1 2
2 3
3 10
4 1
for the for-loop central to program:
i = 0 sum = 0 + -2 = -2
sum>bestSum? no
sum<0? yes so sum=0, currentStart = 0(i)+1 = 1,
and continue loop with next value of i
i = 1 sum = 0 + 2 = 2
sum>bestSum? yes so bestSum=2 and bestStart=currentStart=1 and bestEnd=1=1
sum<0? no
1(i)-1(currentStart)+1==M? 1-1+1=1 so no
i = 2 sum = 2+3 = 5
sum>bestSum? yes so bestSum=5, bestStart=currentStart=1, and bestEnd=2
sum<0? no
2(i)-1(currentStart)+1=M? 2-1+1=2 so yes:
sum = sum-a[1(curentstart)] =5-2=3. currentStart++=2.
(sum<0 || a[currentStart]<0)? no
i = 3 sum=3+10=13
sum>bestSum? yes so bestSum=13 and bestStart=currentStart=2 and bestEnd=3
sum<0? no
3(i)-2(currentStart)+1=M? 3-2+1=2 so yes:
sum = sum-a[1(curentstart)] =13-3=10. currentStart++=3.
(sum<0 || a[currentStart]<0)? no
i = 4 sum=10+1=11
sum>bestSum? no
sum<0? no
4(i)-3(currentStart)+1==M? yes but changes to sum and currentStart now are
irrelevent as loop terminates
Thanks again! Just wanted to post a final answer and I was slightly proud for catching the all negative thing.
Each element is looked at most twice (one time in the outer loop, and one time in the while loop).
O(2N) = O(N)
Explanation: each element is added to the current sum. When the sum goes below zero, it is reset to zero. When we hit M length sequence, we try to remove elements from the beginning, until the sum is > 0 and there are no negative elements in the beginning of it.
By the way, when all elements are < 0 inside the array, you should take only the largest negative number. This is a special edge case which I haven't written below.
Beware of bugs in the below code - it only illustrates the idea. I haven't run it.
int sum = 0;
int currentStart = 0;
int bestSum = 0;
int bestStart = 0;
int bestEnd = 0;
for (int i = 0; i < N; i++) {
sum += a[i];
if (sum > bestSum) {
bestSum = sum;
bestStart = currentStart;
bestEnd = i;
}
if (sum < 0) {
sum = 0;
currentStart = i + 1;
continue;
}
//Our sequence length has become equal to M
if (i - currentStart + 1 == M) {
do {
sum -= a[currentStart];
currentStart++;
} while ((sum < 0 || a[currentStart] < 0) && (currentStart <= i));
}
}
I think what you are looking for is discussed in detail here
Find the subsequence with largest sum of elements in an array
I have explained 2 different solutions to resolve this problem with O(N) - linear time.