Here is the code, I keep not getting the correct output from the getMax method.
I fill an array with the sum of the int values of an ArrayList, then check which one of them is the smallest and the biggest, finally outputting them and pruning away the decimal places, which might cause errors maybe?
Code might be bad, I'm a noob:
public static void miniMaxSum(ArrayList<Integer> arr) {
double[] acc = new double[arr.size()];
for (int i=0; i<arr.size(); i++){
for (int j=0; j<arr.size(); j++){
acc[i] += arr.get(j);
}
acc[i] -= arr.get(i);
}
//double min = acc[arr.size()-1];
//double max = acc[0];
System.out.printf("%.0f", getMin(acc));
System.out.print(" ");
System.out.printf("%.0f", getMax(acc));
}
public static double getMin(double[] acc){
double min = 0;
for (int j=0; j<acc.length; j++){
for (int i=0; i<acc.length; i++){
if (acc[i] > acc[j]){
min = acc[j];
} else {
min = acc[i];
}
}
}
return min;
}
public static double getMax(double[] acc){
double max = 0;
for (int j=0; j<acc.length; j++){
for (int i=0; i<acc.length; i++){
if (acc[i] > acc[j]){
max = acc[i];
System.out.println(max);
}
else {
max = acc[j];
}
}
}
return max;
}
Method to do the checks yourself
public static double findMax(double[] data) {
double max = Double.MIN_VALUE;
for (double val : data) {
if (val > max) {
max = val;
}
}
return max;
}
Using the Math utility
public static double findMax2(double[] data) {
double max = Double.MIN_VALUE;
for (double val : data) {
max = Math.max(val, max);
}
return max;
}
Using streams
public static double findMax3(double[] data) {
return Arrays.stream(data).max().getAsDouble();
}
Doing your own checks
public static double findMin(double[] data) {
double min = Double.MAX_VALUE;
for (double val : data) {
if (val < min) {
min = val;
}
}
return min;
}
Using Math utility
public static double findMin2(double[] data) {
double min = Double.MAX_VALUE;
for (double val : data) {
min = Math.min(val, min);
}
return min;
}
Using streams
public static double findMin3(double[] data) {
return Arrays.stream(data).min().getAsDouble();
}
You can do everything you want do do in a single loop. First calculate the sum for each value and then check for that sum if it is a new maximum and/ or minimum value. If any of these option is true, update the respective maximum or minimum value.
import java.util.*;
public class Application {
public static void main(String[] args) {
var test = new double[]{10d, 4.43d, 5.3d, -6.8d, 7.1d, 8.7d, 8.1d, 234d, -3.9d, -455.3d};
minMaxSum(test);
}
public static void minMaxSum(double[] arr) {
double acc = 0;
// initialize the minimal value with the maximal value
double min = Double.MAX_VALUE;
// initialize the biggest value with the smallest possible value
double max = Double.MIN_VALUE;
var sum = new double[arr.length];
// a single for loop
for (int i = 0; i < arr.length; i++) {
var cur = arr[i];
// sum up adding the current value
acc += cur;
// save the current value in new array so we can verify the result (not actually required for the algorithm)
sum[i] = acc;
// if something is smaller than what we've already encountered => set new smallest value
if(acc < min) min = acc;
// if something is bigger than what we've already encountered => set new biggest value
if(acc < max) max = acc;
}
System.out.printf("""
Original: %s
Prefix-sum: %s
Min: %s
Max: %s
""", Arrays.toString(arr), Arrays.toString(sum), min, max);
}
}
Expected output:
Original: [10.0, 4.43, 5.3, -6.8, 7.1, 8.7, 8.1, 234.0, -3.9, -455.3]
Prefix-sum: [10.0, 14.43, 19.73, 12.93, 20.03, 28.73, 36.83, 270.83, 266.93, -188.37]
Min: -188.37
Max: 270.83
As many people recommended sorting as a viable approach, here some remarks on sorting. First, yes, it would give you a correct result but there is a price to pay which is speed and well it is just an unnecessarily complex solution.
Sorting based on comparisons and without any pre-conditions cannot be done faster than in O(n log n). It is obvious that the solution above needs O(n) time thus is a complexity class faster. Also the constants (which are ignored in big-O notation) are quite small in the above solution, so even if some pre-conditions were met and you could use a special sorting algorithm like Map sort (or alike) which run in O(n) (again: under certain conditions) the above solution would still be faster and, not to mention, much simpler. So don't make your life harder than it needs to be.
You do not need to use nested loops for getMax or getMin functions.
public static double getMax(double[] acc){
double max = Double.MIN_VALUE;
for (double value : acc) {
if( value > max) max = value;
}
return max;
}
if you want to sort the list anyway:
public static void miniMaxSum(ArrayList<Integer> arr) {
if(arr.size() > 0) {
Collections.sort(arr);
System.out.println(arr.get(0));
System.out.println(arr.get(arr.size() - 1));
}
}
Related
I need help figuring out the following problem :
Create a class Statistics.java to implement the StatisticsI.java. Statistics.java contains ArrayList data to store to data objects of Double type, and properties (attributes): count, min, max, mean, std. The implementation has the following specifications.
addData(Double d) adds data d into the array list, and then update the values of count, min, max, mean, and std, using incremental algorithms, i.e. using exiting existing value to calculate new values, rather than calculating by traversal through the data array.
getCount() returns count.
getMin() returns min.
getMax() returns max.
getMean() returns mean.
getSTD() returns std.
stats() computes the count, min, max, mean, and stddev from the data array in one loop, and then sets the values of the properties.
I have the interface
public interface StatisticsI {
void addData(double d);
int getCount();
double getMin();
double getMax();
double getMean();
double getSTD();
void stats();
}
Here is the code I have so far for the implementation part.
import java.util.ArrayList;
public class Statistics implements StatisticsI {
private ArrayList<Double> data;
private long count;
private double min;
private double max;
private double mean;
private double std;
public Statistics() {
data = new ArrayList<Double>();
count = 0;
min = 0;
max = 0;
mean = 0;
std = 0;
}
public void addData(double d) {
data.add(d);
count += 1;
data.set(data.indexOf(min), min);
data.set(data.indexOf(max), max);
data.set(data.indexOf(mean), mean);
data.set(data.indexOf(std), std);
}
public int getCount() {
count = data.size();
return (int) count;
}
public double getMin() {
return min;
}
public double getMax() {
return max;
}
public double getMean() {
int mean = 0;
for (int i = 0; i < data.size(); i++) {
double currentNum = data.get(i);
mean += currentNum;
}
return mean / data.size();
}
public double getSTD() {
{
double avg = getMean();
double t = 0;
for (int i = 0; i < data.size(); i++) {
double numbers = data.get(i);
double value = Math.pow(numbers - avg, 2);
t += value;
}
double std = (double) t / (double) (data.size());
return Math.sqrt(std);
}
}
public void stats() {
count = data.size();
}
}
I am having trouble with the addData and stats methods and I am not sure if I am doing this correctly and I am trying to figure out how to implement it.
My question is how to implement the interface with what is required in the methods.
Update: How do I call the methods from Statistics
Here is the code for the main class
public static void main(String[] args) {
ArrayList<Double> numList = new ArrayList<Double>();
StatisticsI stats = new Statistics();
Random r = new Random();
for(int i = 1; i <= 10; i++) {
numList.add((double) r.nextInt(10000));
}
double count = stats.getCount();
double min = stats.getMin();
double max = stats.getMax();
double mean = stats.getMean();
double std = stats.getSTD();
System.out.println("The count for the list is:"+ count);
System.out.println("The min for the list is:" + min);
System.out.println("The max for the list is:" + max);
System.out.println("The mean for the list is:" + mean);
System.out.println("The standard deviation for the list is:" + std);
}
}
The problem is I don't get any values for my output, I get :
The count for the list is:0.0
The min for the list is:Infinity
The max for the list is:-Infinity
The mean for the list is:0.0
The standard deviation for the list is:NaN
How do I get my output to work?
in addData(..), use "min = Math.min(min, d)". Math.max also exists, but std and mean are trickier. It's probably easiest to calculate those in the getters by iterating the list.
You can update min, max, mean values immediately in addData.
Update It is also possible to use Welford's algorithm to calculate running deviation.
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
double variance = 0.0;
public void addData(double d) {
data.add(d);
count++;
if (d < min) {
min = d;
} else if (d > max) {
max = d;
}
// fixed calculation of running mean and variance by Welford's algorithm
double new_mean = mean + (d - mean) / count;
variance += count < 2 ? 0.0 : (d - mean) * (d - new_mean);
mean = new_mean;
std = count > 1 ? Math.sqrt(variance / (count - 1)) : 0;
}
Or, you can reset all these values in stats() method using the data list.
There is a convenient way to calculate all stats at once via DoubleSummaryStatistics and Java 8 Stream API:
public void stats() {
DoubleSummaryStatistics stats = data.stream().collect(Collectors.summarizingDouble(x -> x));
count = stats.getCount(); // long value returned instead of `int data.size()`
min = stats.getMin();
max = stats.getMax();
mean = stats.getAverage();
std = this.getSTD();
}
public double getSTD() {
double avg = getMean();
double t = 0.0;
for (double d : data) {
t += Math.pow(avg - d, 2);
}
return Math.sqrt(t / getCount());
}
Loop-based "streamless" calculation of stats including "naive" variance calculation algorithm for std could be as follows:
public void stats() {
count = data.size();
min = Double.POSITIVE_INFINITY;
max = Double.NEGATIVE_INFINITY;
mean = 0.0;
variance = 0.0;
double sum = 0.0;
double sq = 0.0;
int i = 0;
for (double d : data) {
min = Math.min(min, d);
max = Math.max(min, d);
i++;
// calculate running mean as above to use in variance
double new_mean = mean + (d - mean) / i;
variance += i < 2 ? 0 : (d - mean) * (d - new_mean);
mean = new_mean;
sum += d;
sq += d * d;
}
System.out.println("running mean=" + mean);
std = count > 1 ? Math.sqrt((sq - mean * mean / count) / (count - 1)) : 0;
mean = count == 0 ? 0 : sum / count;
}
// override STD getter to remove all calculations
public double getSTD() {
return std;
}
Test
Statistics stats = new Statistics();
stats.addData(17);
stats.addData(19);
stats.addData(24);
System.out.println("after addData()");
System.out.println("mean=" + stats.getMean());
System.out.println("std=" + stats.getSTD());
System.out.println("after addData()");
stats.stats();
System.out.println("mean=" + stats.getMean());
System.out.println("std=" + stats.getSTD());
Output
after addData()
mean=20.0
std=3.605551275463989
after stats()
running mean=20.0
mean=20.0
std=3.605551275463989
Today while solving this question on HackerRank I used Array stream .sum() function to sum all the entries and proceeded with my algorithm. But for sum reason I found that my algorithm fails for some cases. I used diff to find out it passes 99% cases and for 1% the output is nearly equal but is less than the original answer. That's why I replaced the stream .sum() with a for loop and unexpectedly it passed all the test cases. I tried but couldn't ascertain this uncertain behaviour.
My implementation using stream.sum() :
public class MandragoraForest {
public static void main(String[] args) {
InputReader in = new InputReader(System.in);
for (int i = in.nextInt(); i > 0; i--) {
int number = in.nextInt();
int[] h = new int[number];
for (int j = 0; j < number; j++) h[j] = in.nextInt();
System.out.println(new MandragoraForestSolver().solve(h));
}
}
}
class MandragoraForestSolver {
public long solve(int[] h) {
if (h.length==1) return h[0];
Arrays.parallelSort(h);
long sum = Arrays.stream(h)
.sum();
long ans = -1;
for (long i=0, strength = 2; i<h.length; i++, strength++) {
sum -= h[(int)i];
ans = Math.max(ans, strength * sum);
}
return ans;
}
}
Implementation without Java stream :
public class MandragoraForest {
public static void main(String[] args) {
InputReader in = new InputReader(System.in);
for (int i = in.nextInt(); i > 0; i--) {
int number = in.nextInt();
int[] h = new int[number];
long sum = 0;
for (int j = 0; j < number; j++) {
h[j] = in.nextInt();
sum += h[j];
}
System.out.println(new MandragoraForestSolver().solve(h, sum));
}
}
}
class MandragoraForestSolver {
public long solve(int[] h, long sum) {
if (h.length==1) return h[0];
Arrays.parallelSort(h);
long ans = -1;
for (long i=0, strength = 2; i<h.length; i++, strength++) {
sum -= h[(int)i];
ans = Math.max(ans, strength * sum);
}
return ans;
}
}
Is there something that I'am missing out ? What could be the reason for this behaviour?
There is one significant difference between using a stream and a loop - the possibility of arithmetic overflow.
Arrays.stream(int[]) returns an IntStream, whose sum() method returns an int result. If the sum exceeds Integer.MAX_VALUE, a silent integer overflow will occur.
However your loop sums by adding int values to a long total, which would not suffer from arithmetic overflow.
The sum of integers in one of the tests must exceed Integer.MAX_VALUE, testing that a long is used to (correctly) calculate the total.
If you want to use a stream to sum, you need to convert the IntStream to a LongStream, which you can do like this:
long sum = Arrays.stream(big).asLongStream().sum();
I have to create classes to be implemented with the main class someone else has and for some reason I am not getting the right outputs, I'm not sure is my calculations are off which I don't think they are or my insert class is wrong.
Expected Output:
Median = 44.5
Mean = 49.300
SD = 30.581
Actual Output:
Median = 0.0
Mean = 0.967
SD = 4.712
public class StatPackage {
int count;
double [] scores;
final int MAX = 500;
StatPackage() {
count = 0;
scores = new double[MAX];
}
public void insert (double value) {
if (count < MAX){
scores[count] = value;
++ count;
}
}
public double Mean () {
double sum = 0;
//For loop for calculating average or mean
for(int i = 0; i < scores.length; i++){
sum += (scores[i]);
count++;
}
double average = sum/count;
return average;
}
public double Median() {
int min;
int tmp;
int size;
for (int i = 0; i < scores.length - 1; i ++)
{
min = i;
for (int pos = i + 1; pos < scores.length; pos ++)
if (scores [pos] < scores [min])
min = pos;
tmp = (int)scores [min];
scores [min] = scores [i];
scores [i] = tmp;
}
double median = 0;
if (scores.length % 2 == 0){
median = (scores[scores.length/2-1] + scores[scores.length/2])/2;
}
else {
median = (scores[((scores.length/2))]);
}
return median;
}
public double Variance () {
double variance = 0;
double sum = 0;
//For loop for getting the variance
for(int i = 0; i < scores.length; i++){
sum += scores[i];
variance += scores[i] * scores[i];
count++;
}
double varianceFinal = ((variance/count)-(sum*sum)/(count*count));
return (varianceFinal);
}
public double StdDev (double variance) {
double sum = 0;
for(int i = 0; i < scores.length; i++){
sum += scores[i];
variance += scores[i] * scores[i];
count++;
}
double varianceFinal = ((variance/count)-(sum*sum)/(count*count));
return Math.sqrt(varianceFinal);
}
}
The length of your scores array is 500, so every time you are using it in a calculation you are running that 500 times. You need to make your loop continuation conditions dependent on the number of values in the array, no the actual length of the array. I would be careful of your variable naming as well, you are using count in two places sometimes and it has global scope! This method stores the number of values in the array in the count variable:
public void insert (double value) {
if (count < MAX){
scores[count] = value;
++count;
}
}
So use the count variable as the loop-continuation condition when you are getting values from the array, like so:
public double mean() {
double sum = 0;
//For loop for calculating average or mean
for(int i = 0; i < count; i++){
sum += (scores[i]);
}
double average = sum / count;
return average;
}
That should help a little, I don't have time to check out your other methods but maybe this will give you a good starting place. I figured out what was happening by inserting print statements in your methods to make sure the values were as expected. It's a helpful thing to do when debugging. Your mean() method with the print statements looks like this:
public double mean() {
double sum = 0;
//For loop for calculating average or mean
for(int i = 0; i < count; i++){
sum += (scores[i]);
}
// print statements for debugging
System.out.println("count is " + count);
System.out.println("sum is " + sum);
double average = sum / count;
return average;
}
Because the solution is easily found by debugging, I will only give you a hint:
The mean of 3, 4 and 5 is 4: (3+4+5)/3, not (3+4+5)/(n*3) where
n is a positive integer.
If you look at your mean and std and divide it by the expected result, you will see it's a rounded number.
Once you find the solution to 1 problem, you will immediately know why the other results are faulty as well =)
I've created two different methods that calculate random monthly savings, and the monthly interest on those savings and saves each to its own array. I would like to have a new method that returns the last element in the calculateInterest array (as its the cumulative total of savings and interest in a year), so i can use that specific number in a different part of my program later.
So her is what i have so far. My methods for calculating savings and interest work just fine but i don't know how to actually get the value and not just the array number (which is all I've been able to call) in my last method.
Any help or direction would be greatly appreciated!
public class EmployeeSavings extends AddressBook {
private double accountValue;
private double[] monthlyInterests = new double [12];
private double[] monthlySavings = new double[12];
private static final double MONTHLY_RATE= 0.00417;
public double[] generateMonthlySavings() {
double min = 100;
double max = 800;
double range = (max - min);
for (int i = 0; i < monthlySavings.length; i++) {
monthlySavings[i] = (Math.random() * range) + min;
System.out.println(monthlySavings[i]);
}
return monthlySavings;
}
public double[] calculateInterest() {
double count = 0;
for (int i = 0; i < monthlyInterests.length; i++) {
if (i <= monthlyInterests.length)
count = (monthlySavings[i] + count) * (1 + MONTHLY_RATE);
System.out.println(count);
}
return monthlyInterests;
}
public double[] getMonthlyInterest(){
return monthlyInterests;
}
public double[] getMonthlySavings() {
return monthlySavings;
}
// Would like to return total value here
public double getAccountValue() {
for (int i = 12; i <= getMonthlyInterest().length; i++) {
accountValue = i;
}
return accountValue;
}
If your java version is 8 I would do it like so
public double getAccountValue() {
return DoubleStream.of( getMonthlyInterest() ).sum();
}
It's much shorter and I think it's also more readable. But if your java version isn't 8 do something like this
double[] d = getMonthlyInterest();
double value = 0d;
for (int i = 0; i < d.length; i++) {
value += d[i]; // d[i] returns value which has i index in array d.
}
I need to get the index value of the minimum value in my arraylist in Java. MY arraylist holds several floats, and I'm trying to think of a way I can get the index number of the smallest float so I can use that index number elsewhere in my code. I'm a beginner, so please don't hate me. Thanks!
You can use Collections.min and List.indexOf:
int minIndex = list.indexOf(Collections.min(list));
If you want to traverse the list only once (the above may traverse it twice):
public static <T extends Comparable<T>> int findMinIndex(final List<T> xs) {
int minIndex;
if (xs.isEmpty()) {
minIndex = -1;
} else {
final ListIterator<T> itr = xs.listIterator();
T min = itr.next(); // first element as the current minimum
minIndex = itr.previousIndex();
while (itr.hasNext()) {
final T curr = itr.next();
if (curr.compareTo(min) < 0) {
min = curr;
minIndex = itr.previousIndex();
}
}
}
return minIndex;
}
This should do it using built in functions.
public static int minIndex (ArrayList<Float> list) {
return list.indexOf (Collections.min(list)); }
try this:
public int getIndexOfMin(List<Float> data) {
float min = Float.MAX_VALUE;
int index = -1;
for (int i = 0; i < data.size(); i++) {
Float f = data.get(i);
if (Float.compare(f.floatValue(), min) < 0) {
min = f.floatValue();
index = i;
}
}
return index;
}
There is an easier way to find a min integer in array list:
int min = array.get(0);
for (int i : array){
min = min < i ? min : i;
}
public static int minIndex (ArrayList<Float> list) {
return list.indexOf (Collections.min(list));
}
System.out.println("Min = " + list.get(minIndex(list));
Declare a arraylist with Floats.
Collection.min() - finding the minimum element in the list.
List.indexOf() - finding the index of the minimum element.
public class Test {
public static void main(String[] args) {
ArrayList<Float> ary = new ArrayList<Float>();
ary.add((float) 3.0);
ary.add((float) 6);
ary.add((float) 2);
ary.add((float) 1.3);
ary.add((float) 4.2);
int indx = minIndex(a);
System.out.println(indx);
}
public static int minIndex(ArrayList<Float> list) {
return list.indexOf(Collections.min(list));
}
}
You have to traverse the whole array and keep two auxiliary values:
The minimum value you find (on your way towards the end)
The index of the place where you found the min value
Suppose your array is called myArray. At the end of this code minIndex has the index of the smallest value.
var min = Number.MAX_VALUE; //the largest number possible in JavaScript
var minIndex = -1;
for (int i=0; i<myArray.length; i++){
if (myArray[i] < min){
min = myArray[i];
minIndex = i;
}
}
This is assuming the worst case scenario: a totally random array. It is an O(n) algorithm or order n algorithm, meaning that if you have n elements in your array, then you have to look at all of them before knowing your answer. O(n) algorithms are the worst ones because they take a lot of time to solve the problem.
If your array is sorted or has any other specific structure, then the algorithm can be optimized to be faster.
Having said that, though, unless you have a huge array of thousands of values then don't worry about optimization since the difference between an O(n) algorithm and a faster one would not be noticeable.
Here's what I do. I find the minimum first then after the minimum is found, it is removed from ArrayList.
ArrayList<Integer> a = new ArrayList<>();
a.add(3);
a.add(6);
a.add(2);
a.add(5);
while (a.size() > 0) {
int min = 1000;
for (int b:a) {
if (b < min)
min = b;
}
System.out.println("minimum: " + min);
System.out.println("index of min: " + a.indexOf((Integer) min));
a.remove((Integer) min);
}