I'm working on making a program to roll 4 6 sided dice and do some simple math and logic with them. I was running a very rough draft of the program and started to notice that the number of rolls would be inconsistent. In particular I would sometimes wont get the smallest value or get two
If looked around for a solution online to no avail. I even copied the code from other examples on how to find the smallest value
public class test {
private static int dice(int s) {
int num = 0;
Random random = new Random();
num = random.nextInt(s);
num = num + 1;
return num;
}
public static void main(String[] args) {
List<Integer> rolls = new ArrayList<Integer>();
for (int i = 0; i != 4; i++) {
rolls.add(dice(6));
}
for (Integer roll : rolls) {
System.out.println(roll);
}
int min = rolls.get(0);
int index = 0;
for (int x = 0; x < rolls.size(); x++) {
if (rolls.get(x) < min) {
min = rolls.get(x);
index = x;
System.out.println("Smallest: " + min);
}
}
int sum = 0;
for (int x : rolls) {
sum += x;
}
System.out.println("Sum:" + sum);
}
}
This should generate 4 rolls of 6 sided dice. Then it should find the smallest value print that, then calculate the sum and print it
Check out this bit of code:
int min = rolls.get(0);
int index = 0;
for(int x = 0; x<rolls.size(); x++){
if(rolls.get(x) < min){
min=rolls.get(x);
index = x;
System.out.println("Smallest: " + min);
}
}
What happens if rolls.get(0); is your minimum roll? In that case, if(rolls.get(x) < min) will always be false, and you'll never print "Smallest...".
Also note that every time you find a roll that is smaller than the last one you looked at, you print out "Smallest..." again, so if you have multiple dice in descending size, you'll print that line out multiple times.
Set your initial min value to 7, so you're guaranteed to have a min value that is smaller than the initial state. And then, instead of printing inside your loop, save the min and print "Smallest..." once the loop is finished:
// Be aware that this code doesn't work correctly if your List is empty.
int min = 7; // You could also set this to rolls.get(0) and start your loop at 1
for (int x = 0; x < rolls.size(); x++) {
if (rolls.get(x) < min) {
min = rolls.get(x);
}
}
System.out.println("Smallest: " + min);
(I also removed index, because it's not being used anywhere in your code).
If you wanted to be a bit more modern with this (and also more robust), you could also do:
rolls.stream()
.min(Integer::compareTo)
.ifPresent(min -> System.out.println("Smallest: " + min));
That will handle the case of rolls being empty by just not printing anything.
Related
I'm writing a code to find the mean, median and mode of an array of randomly generated ints (user inputs a size for the array and a range between which random numbers are to be generated it generate numbers between 3-22 randomly. I have not had too much trouble writing code for a mean or median but I cannot seem to be able to write code to calculate the mode (most commonly occurring number). Can anyone help or show/put code for how to calculate the mode of a randomly generated array of ints without having to create a method for yourself in the code? Thanks. Here is what I have so far (code that finds the mean and median):
public class ArraysIntsMeanMedianAndMode {
public static void main(String[] args) {
int ArraySize;
int min;
int max;
double x;
// To get the Size and range of numbers for the randomly genereated ints in the array.
Scanner sc = new Scanner(System.in);
System.out.println("What size should the array be?");
ArraySize = sc.nextInt();
System.out.println("Please enter a minimum value for the range of ints.");
min = sc.nextInt();
System.out.println("Please enter a maximum value for the range of ints.");
max = sc.nextInt();
//Making the array and filling it based on the user inputs
int[] MMMarray = new int[ArraySize];
int total = 0;
for (int i = 0; i < ArraySize; i++) {
x = (int) (Math.random() * ((max - min) + 1)) + min;
System.out.println(x);
int RandoNums = (int) x;
total = total + RandoNums;
MMMarray[i] = RandoNums;
}
//Finding mean/average
double Mean = (total + 0.0) / ArraySize;
System.out.println("The mean is: " + Mean);
//Finding Median/Middle number
Arrays.sort(MMMarray);
System.out.println(Arrays.toString(MMMarray));
if (ArraySize % 2 == 0) {
System.out.println("The median is: " + ((MMMarray[(ArraySize / 2)] + 0.0) + MMMarray[(ArraySize / 2) - 1]) / 2 + ".");
} else System.out.println("The median is: " + MMMarray[ArraySize / 2] + ".");
//How to find mode????????
Finding mode of unsorted array of int:
int freq = 0;
int value = 0;
int length = MMMArray.length;
for (int outer = 0; outer < length; outer++)
{
int tempFreq = 0;
for (int inner = 0; inner < length; inner++)
{
if (MMMArray[outer] == MMMArray[inner])
{
tempFreq++;
}
}
if (tempFreq > freq)
{
freq = tempFreq;
value = MMMArray[outer];
}
}
System.out.println("Mode is " + value + ", which appears " + freq + " times.");
Because you have already sorted the array to calculate the median, the problem of finding the mode(s) becomes equivalent to finding the longest consecutive streak of the same number. So, for example, if you have [1, 1, 2, 2, 2, 3, 5, 5, 21], there are three consecutive 2's, which is longer than any other run, so 2 is the mode.
To find the longest run, you can pass over the data once more, not reading any element twice. I'm adapting the code of Litvin and Litvin ever so slightly to use your array name, to count a run of 1 as a run, and to report what number the mode is rather than where it is in the array. You can drop this code in right where you ask your question, after the median has been calculated.
// at this point MMMArray is a sorted, nonempty array of int, because it was already sorted to find the median
int maxRunStart = 0, maxRunLength = 1;
int runStart = 0, runLength = 1;
for (int i = 1; i <= MMMArray.length; i++) //what they do here by using <=
//rather than < is worth reflecting upon
//it handles the case of the biggest run being at the end within the loop body
{
if (i < MMMArray.length && MMMArray[i] == MMMArray[i - 1])//notice how the boolean short-circuit prevents reading beyond the end of the array
{
runLength++;
}
else
{
if (runLength > maxRunLength)
{
maxRunStart = runStart;
maxRunLength = runLength;
}
runStart = i;
runLength = 1;
}
}
System.out.println("The mode is: " + MMMArray[maxRunStart] + ".");
}
Now here is something new to ponder. Suppose MMMArray contains [1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3]. This code (or that of MarsAtomic) will report 1 is the only mode. But the data is bimodal, and 3 is the mode as much as 1 is. One way to adapt the code would be to store the mode(s) in an array list (or an array, because we know up front there cannot be more modes than numbers). I think it is simpler (not more efficient, just easier not to mess up and without introducing another non-simple type) to make one more pass over the data. If you want that, then after the first for loop, instead of the println of the one mode, insert the following:
runLength = 1;
runStart = 0;
for (int i = 1; i <= MMMArray.length; i++)
{
if (i < MMMArray.length && MMMArray[i] == MMMArray[i - 1])
{
runLength++;
}
else
{
if (runLength == maxRunLength)
{
System.out.println("The mode is: " + MMMArray[runStart] + ".");
}
runStart = i;
runLength = 1;
}
}
Below is what I have so far. The instructions are to create a simple java program that calculates the avg of a variable quantity of ints. Args array for main, no Scanner object, find and display highest and lowest value. Static method that takes user input as argument & returns values. Should display welcome message at launch.
So I think the start of my code is correct! It compiles for me. But I'm not sure how to get user input w/o scanner. I assume I need to use an array in the static method to translate the input into an argument. Which at execution would be java CalculateAverage 1, 2, 5, 9, 20?
And then would I call MATH? So I can display all the values of min max & avg? Am I on the right track..? The questions are specific in the code. Sorry, first time posting here!
public class CalculateAverage {
public static void main(String[] args) {
System.out.print("Hello welcome to the Average Calculator");
int[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
//do i just keep going and adding letters til j?
//or is there an easier way to do this..?
minArray(array);
maxArray(array);
sumArray(array);
avgArray(array);
}
public static double maxArray(double[] array){
double max = Double.NEGATIVE_INFINITY;
//tbh i saw this on a tutorial, idk if NEGATIVE_INFINITY would
//work for me?
for (int i = 0; i < n; i++)
if (array[i] > max) max = array[i];
System.out.println("The maximum of your array is:" + max);
}
public static double avgArray(double[] array){
double sum = 0.0;
for(int i = 0; i < n; i++)
sum += array[i];
double avg = sum / n;
System.out.println("The average value of your array is: " + avg);
} //then i would make another static for the min but probably before max
}
From the command line, you want to execute
javac CalculateAverage.java
to have Java compile the class and prepare to run it. Then you can execute the code with
java CalculateAverage arg0 arg1 arg2 ...
Now, in your main( string[] args ) method, I see you're creating an array with 11 elements. This is not necessary, and it is not ideal - what if the user gives more than 11 arguments when they're running the program? The better way to do this is:
int[] array = new int[ args.length ]()
This creates a new array of ints, of the same length as the array args - every array has that property length that states how many elements the array has. Now, we haven't actually put anything in array yet, but we know that it has space for the same number of arguments as the program gave. Now, to initialize each element:
for(int i = 0; i < args.length; i++) {
array[i] = Integer.parseInt(args[i])
}
A for loop creates a variable i (this is the int i = 0 part), initialized to 0, and then executes the code inside the curly brackets. After it's done, it increases the value of i by one (this is the i++ part), and runs the code inside the curly brackets again, continuously, until the condition i < args.length is false. Altogether, this iterates through every element of args and initializes the corresponding element of array.
Now, you could use the Math module to do the calculations for you, but you're almost there in doing it yourself. Here's a slight touch-up to maxArray, for example:
public static int maxarray(int[] array) {
int max = array[0]
for (int i = 1; i < array.length; i++) {
if (array[i] > max) max = array[i];
}
}
System.out.println("The maximum of your array is:" + max);
}
I'm using int here because the inputs were ints. In general you should probably make sure that everything is the same type of variable; either make all the numbers ints or make them all doubles, but don't try to go back and forth between them.
You don't actually need negative infinity for anything; you can just start with the first number in your array, call that the maximum, and then for every number afterwards, replace the maximum if it's larger. We use the for loop in the same way here, to iterate over the entire array.
Similarly, you're doing avgArray(double[] array) correctly already - except that I don't know where you got the variable n from (you should be using array.length again).
Overall, I recommend looking back over your notes for this class so far, and carefully make sure you know what everything means and how it applies to this example. Review what you've been taught about how Arrays work; and about the differences between ints and doubles.
This is what I would do. Hopefully the code is simple and self-explanatory but let me know if any questions:
public static void main(String[] args) {
System.out.println("Hello welcome to the Average Calculator");
int numArgs = args.length; //Since args is an array we can get the number of elements with .length
int min = Integer.MAX_VALUE; //The maximum possible value an int can be
int max = Integer.MIN_VALUE; //The minimum possible value an int can be
double total = 0;
for(int i = 0; i < numArgs; i++) {
int nextI = Integer.parseInt(args[i]);
total += nextI;
if(nextI < min) {
min = nextI;
}
if(nextI > max) {
max = nextI;
}
}
System.out.println("The average is: " + total/numArgs);
System.out.println("The min is: " + min);
System.out.println("The max is: " + max);
}
Then, you would run the code like this:
java CalculateAverages 1 2 3 4 5 6 7 8 9
Hello welcome to the Average Calculator
The average is: 5.0
The min is: 1
The max is: 9
Edit:
The instructions said "To find these value, make static methods that
take the user input as arguments & returns the value"
public static void main(String[] args) {
int numArgs = args.length;
int[] userIntInputs = new int[numArgs];
for(int i = 0; i < numArgs; i++) {
userIntInputs[i] = Integer.parseInt(args[i]);
}
System.out.println("The average is: " + getInputAverage(userIntInputs));
System.out.println("The min is: " + getInputMin(userIntInputs));
System.out.println("The max is: " + getInputMax(userIntInputs));
}
private static int getInputMax(int[] userIntInputs) {
int max = Integer.MIN_VALUE;
for(int i = 0; i < userIntInputs.length; i++) {
if(userIntInputs[i] > max) {
max = userIntInputs[i];
}
}
return max;
}
private static int getInputMin(int[] userIntInputs) {
int min = Integer.MAX_VALUE;
for(int i = 0; i < userIntInputs.length; i++) {
if(userIntInputs[i] < min) {
min = userIntInputs[i];
}
}
return min;
}
private static double getInputAverage(int[] userIntInputs) {
double total = 0;
for(int i = 0; i < userIntInputs.length; i++) {
total += userIntInputs[i];
}
return total/userIntInputs.length;
}
One Method Alternative
Idk if she means to make a method for each value or one method!
Yeah teachers can be confusing all right. Here's a one method approach...
public static void main(String[] args) {
int numArgs = args.length;
int[] userIntInputs = new int[numArgs];
for(int i = 0; i < numArgs; i++) {
userIntInputs[i] = Integer.parseInt(args[i]);
}
Object[] inputMetrics = getInputMetrics(userIntInputs);
System.out.println("The average is: " + inputMetrics[0]);
System.out.println("The min is: " + inputMetrics[1]);
System.out.println("The max is: " + inputMetrics[2]);
}
private static Object[] getInputMetrics(int[] userIntInputs) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
double total = 0;
for(int i = 0; i < userIntInputs.length; i++) {
int nextI = userIntInputs[i];
total += nextI;
if(nextI < min) {
min = nextI;
}
if(nextI > max) {
max = nextI;
}
}
Object[] metrics = {total/userIntInputs.length, min, max};
return metrics;
}
Simplicity is IMHO the best way. This does the whole thing:
DoubleSummaryStatistics stats = Arrays.stream(args)
.collect(Collectors.summarizingDouble(Double::parseDouble));
System.out.println("The minimum of your array is: "+ stats.getMin());
System.out.println("The maximum of your array is: "+ stats.getMax());
System.out.println("The sum of your array is: "+ stats.getSum());
System.out.println("The average of your array is: "+ stats.getAverage());
When there's a built-in library to handle something, use it.
When I try to run this program in java it will not work even though there are no errors in eclipse.
import java.util.Scanner;
public class Project1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter how many numbers: ");
int x = input.nextInt();
double[] numbers = new double[x];
double[] orderednumbers = new double[x];
double total = 0;
for (int i = 0; i < numbers.length; i++) {
System.out.print("Please enter number " + (i + 1) + ": ");
numbers[i] = input.nextDouble();
total += numbers[i];
}
double mean = (total / x);
System.out.println("Mean: " + mean);
orderednumbers[x] = 0;
for (int counter = 0; counter < numbers.length; counter++) {
if (numbers[counter] > orderednumbers[x]) {
orderednumbers[x] = numbers[counter];
orderednumbers[x] = orderednumbers[x];
}
}
System.out.println("Maximum: " + orderednumbers[x]);
}
}
This is what's called a runtime error. Sure, it compiles... but for this code you need to be careful with how you handle the array. Your code gave me an ArrayOutOfBoundsException.
Note that you set x early in the code to the length of the array, then go and set orderednumbers[x] to 0. This will give you an ArrayIndexOutOfBoundsException, as since Java array indices are zero-based (i.e. element #1 has index 0, and can be accessed with orderednumbers[0]), the length of an array isn't a valid index.
Also, your code for swapping the two numbers in the sort is incorrect; you'll need a temporary variable to store the result. Otherwise, you'll end up making the two places in the array hold the same value.
Try making it this:
int temp = orderednumbers[x];
orderednumbers[x] = numbers[counter];
orderednumbers[x] = temp;
Note that your statement at the end of the if block:
orderednumbers[x] = orderednumbers[x];
won't accomplish anything.
Two consecutive integers are natural successors if the second is the successor of the first in the sequence of natural numbers (1 and 2 are natural successors). Write a program that reads a number N followed by N integers, and then prints the length of the longest sequence of consecutive natural successors.
import java.util.Scanner;
public class objects {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int x = scan.nextInt();
int nmbr[] = new int[x];
for(int f=0;f<nmbr.length;f++)
nmbr[f]=scan.nextInt();
int counter = 0;
int max = 0;
for (int i = 0; i < nmbr.length - 1; i++) {
if (nmbr[i] == (nmbr[i + 1]-1))
counter++;
else
counter = 0;
if (counter > max)
max = (counter+1);
}
System.out.println(max);
}
}
Why is my code still printing the counter without adding one? I am not finding the mistake
sample run:
7 2 3 5 6 7 9 10
2
it is printing 2 instead of 3.
When you see the first number out of sequence, you should reset counter to 1, not 0 - as it's the start of a sequence with length at least 1. You then need to also change the code which changes max:
if (counter > max) {
counter = max;
}
After all, you just want max to be the maximum value of counter.
(I would strongly recommend using braces for every if statement, by the way - it's easier to avoid mistakes that way.)
import java.util.Scanner;
public class objects {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int x = scan.nextInt();
int nmbr[] = new int[x];
for(int f=0;f<nmbr.length;f++) {
nmbr[f]=scan.nextInt();
}
int counter = 0;
int max = 0;
for (int i = 0; i < nmbr.length - 1; i++) {
if (nmbr[i] == (nmbr[i + 1]-1)) {
counter++;
} else {
if (counter > max)
max = (counter+1);
counter = 0;
}
}
System.out.println(max);
}
}
Just a minor error in your logic there, you were updating max every single time the counter was greater than max, so the next time if the sequence comes to an end, it actually fails to register as the longest sequence. Just reorder it as I have done and it works.
Start your conter from 1. because if you start from 0 then it means you are not counting the 1st value.
else
counter = 1;
And Change the dont increment your counter when assigning to max.
max =counter;
Your maximum condition is incorrect:
if (counter > max)
max = (counter+1);
You compare max with counter and assign counter+1. This way when max is equal to 2 it can't be updated with 2+1.
Probably you should use:
if (counter + 1 > max)
max = (counter+1);
P.S.: Your question doesn't show research effort. You could use debug output to understand what is going on with your program. Simplistic example:
for (int i = 0; i < nmbr.length - 1; i++) {
if (nmbr[i] == (nmbr[i + 1]-1))
counter++;
else
counter = 0;
System.out.println("Current value: "+counter);
if (counter > max) {
max = (counter+1);
System.out.println("New max value: "+max);
}
}
This was an easy one and already pointed out in previous answers you are wrongly setting the value of counter in your code.
Run your code through a debugger to keep a track of variable values of what you are expecting from your program versus what you are actually getting.
Stepping through each line of code can help you understand your mistakes better.
you don't take into account the first number, in this case 5
when i == 2 its the start of the sequence, however, nmbr[1] is 3 therfore counter will stil be 0
start the counter to be 1 (this is logic, since the smallest sequence is 1)
you need to change the if to be:
import java.util.Scanner;
public class objects {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int x = scan.nextInt();
int nmbr[] = new int[x];
for(int f=0;f<nmbr.length;f++)
nmbr[f]=scan.nextInt();
int counter = 1;
int max = 1;
for (int i = 0; i < nmbr.length - 1; i++) {
if (nmbr[i] == (nmbr[i + 1]-1))
counter++;
else
counter = 1;
if (counter > max)
max = counter;
}
System.out.println(max);
}
}
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.