how to display the closest pair product in array - java

import java.util.Scanner;
class my
{
public static void main()
{
Scanner sc = new Scanner(System.in);
int t;
int a[] = new int[5];
int l = a.length;
int prod[] = new int[100];
int index[] = new int[100];
int n;
System.out.println("enter a elements into array ");
for(int i = 0;i<5;i++)
{
a[i] = sc.nextInt();
}
for(int i = 0 ;i<4;i++)
{
for(int j = 0;j<(4-i);j++)
{
if(a[j]>a[j+1])
{
t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
}
System.out.println("enter a number");
n = sc.nextInt();
for(int i = 0;i<l-1;i++)
{
prod[i] = a[i]*a[i+1];
index[i] = a[i];
index[i+1]=a[i+1];
}
for(int i = 0;i<l;i++)
{
if(prod[i]!=0)
System.out.println(prod[i]);
}
for(int i = 0;i<l-1;i++)
{
if(n>prod[i]&&n<=prod[i+1])
System.out.println(index[i+1]+"\t"+index[i+2]);
}
}
}
if want to display the closest pair product in array, which nearest to the entered number. but when i entered array element 1, 2 ,3, 5, 4
and after enter the array i am entering number 8 it is display 3, 4 pair from array instead of 5,2. answer would be 5,2 because the product of 5 * 2 is 10 which is closest to entered number is 8.

The problem with the code is that it is just calculating the product of two consecutive elements and than your are simply comparing that with the product of other elements, which is not a correct way.
Since you sort the array a better way to do it is, by using the logic of binary search. And the logic that the product of pair closest to x will have the least difference.
The algorithm which you can use is as followed:
1. Make a variable difference and initialize to Integer.MAX_VALUE;
2. Now traverse the array from both the direction, i.e set index of left = 0, and right = arr.length -1.
3. Loop while left < right.
(a) If abs((arr[left] * arr[right]) - x) < difference
then update difference and result
(b) if((arr[left] * arr[right]) < x) then
left++
(c) Else right--
Time Complexity : O(nlog(n))

I don't understand why you have so many loops and so many variables in your solution. You also don't need to sort the array a.
In pseudo code:
var a[]
var n
var closest = MAX_INTEGER
var closest_i
var closest_j
for i in range [0, a.length)
for j in range [i + 1, a.length)
var distance = abs(a[i] * a[j] - n)
if distance < closest
closest = distance
closest_i = i
closest_j = j
Note that this has O(n) time complexity.

Related

Solving a matrix equation in Java

I have been trying to implement the given formula in JAVA but i was unsuccessful. Can someone help me find what I am doing wrong?
Do i need to shift the summation index and if so how?
My code:
public final class LinearSystem {
private LinearSystem() {
}
public static int[] solve(int [][]A , int []y) {
int n = A.length;
int[] x = new int[n];
for (int i = 0 ; i < n; i++) {
x[i] = 0;
int sum = 0;
for(int k = i + 1 ; k == n; k++) {
sum += A[i][k]*x[k]; // **java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3**
}
x[i] = 1/A[i][i] * (y[i] - sum);
}
return x;
}
public static void main(String[] args) {
int[][]A = new int[][]{{2,-1,-3},{0,4,-1},{0,0,3}};
int [] y = new int[] {4,-1,23};
System.out.println(Arrays.toString(solve(A,y))); **// awaited result [2, -3, 1]**
}
}
Just trying to collect all my comments under the question into one coherent answer, since there are quite a few different mistakes in your program.
This method of solving linear equations relies on your calculating the components of the answer in reverse order - that is, from bottom to top. That's because each x[i] value depends on the values below it in the vector, but not on the values above it. So your outer loop, where you iterate over the x values needs to start at the biggest index, and work down to the smallest. In other words, instead of being for (int i = 0; i < n; i++), it needs to be for (int i = n - 1; i >= 0; i++).
The inner loop has the wrong stopping condition. With a for loop, the part between the two semicolons is the condition to continue iterating, not the condition to stop. So instead of for(int k = i + 1; k == n; k++), you need for(int k = i + 1; k < n; k++).
You're doing an integer division at the beginning of 1 / A[i][i] * (y[i] - sum);, which means the value is rounded to an integer before carrying on. When you divide 1 by another integer, you always get -1, 0 or 1 because of the rounding, and that makes your answer incorrect. The fix from point 4 below will deal with this.
The formula relies on the mathematical accuracy that comes with working with either floating point types or decimal types. Integers aren't going to be accurate. So you need to change the declarations of some of your variables, as follows.
public static double[] solve(double[][] A, double[] y)
double x[] = new double[n];
double sum = 0.0;
along with the corresponding changes in the main method.
First, you need the second loop to go until k < n, otherwise this throws the ArrayOutOfBounds Exceptions.
Second, you need to calculate your x in reverse order as #Dawood ibn Kareem said.
Also, you probably want x[] to be a double-array to not only get 0-values as result.
I am sorry I don't know much about math side so I couldn't fix it to the right solution but I noticed a few things wrong about your code.
1-You shouldn't initialize your arrays as integer arrays, because you will be doing integer division all over the place. For example 1/A[i][i] will result in 0 even if A[i][i] = 2
2-You shouldn't write k == n, if you do it like this then your for loop will only execute if k equals n, which is impossible for your case.
I think you want to do k < n, which loops from i+1 to the point where k = n - 1
Here is my code:
import java.util.Arrays;
public final class LinearSystem {
private LinearSystem() {
}
public static double[] solve(double [][]A , double []y) {
int n = A.length;
double[] x = new double[n];
for (int i = 0 ; i < n; i++) {
x[i] = 0;
int sum = 0;
for(int k = i + 1 ; k < n; k++) {
sum += A[i][k] * x[k]; // **java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3**
}
x[i] = 1/A[i][i] * (y[i] - sum);
}
return x;
}
public static void main(String[] args) {
double[][]A = new double[][]{{2,-1,-3},{0,4,-1},{0,0,3}};
double [] y = new double[] {4,-1,23};
System.out.println(Arrays.toString(solve(A,y))); // awaited result [2, -3, 1]**
}
}
Remember that arrays are indexed from 0, so the last element is at index n - 1, not n.

Program throws a ArrayIndexOutOfBoundsException when using Bucket Sort on an array that's sorted backwards

I need to run an array that's sorted backwards (I.E. 100, 99, 98, 97 . . . . 3, 2, 1, 0, highest to lowest) through a bucket sort that will sort it lowest to highest. The code that generates the array looks like this:
int n = 100;//Decides how large the arrays fed to the sorts are, minimum value of 100
int k = n - 1;
int howMany = 10;//Decides how many times the sorts are timed whenever the program is run
int[] baseArray = new int[n];
//Loops entire thing as many times as howMany dictates, will refer to it as PRIME LOOP
for (int m = 0; m < howMany; m++) {
for (int i = 0; i < n; i++) //Generates array that's sorted backwards
{
baseArray[i] = k;
k--;
}
int[] bucketArray = new int[n];
for (int i = 0; i < n; i++) {
bucketArray[i] = baseArray[i];
}
bucketSort(bucketArray); //Sends the array to bucket sort (This is line 218)**************
}
Here's the actual bucket sort:
//Bucket Sort
public static void bucketSort(int[] input) {
// get hash codes
final int[] code = hash(input);
// create and initialize buckets to ArrayList: O(n)
List<Integer>[] buckets = new List[code[1]];
for (int i = 0; i < code[1]; i++) {
buckets[i] = new ArrayList();
}
// distribute data into buckets: O(n)
for (int i : input) {
buckets[hash(i, code)].add(i); //This is line 349*******************************************
}
// sort each bucket O(n)
for (List bucket : buckets) {
Collections.sort(bucket);
}
int ndx = 0;
// merge the buckets: O(n)
for (int b = 0; b < buckets.length; b++) {
for (int v : buckets[b]) {
input[ndx++] = v;
}
}
}
private static int[] hash(int[] input) {
int m = input[0];
for (int i = 1; i < input.length; i++) {
if (m < input[i]) {
m = input[i];
}
}
return new int[] { m, (int) Math.sqrt(input.length) };
}
private static int hash(int i, int[] code) {
return (int) ((double) i / code[0] * (code[1] - 1));
}
The first time the code goes through the for-loop (prime loop) bucket sort spits out the array with it properly sorted lowest to highest. However, without fail the second time it goes through the prime loop it gives me an ArrayIndexOutOfBoundsException, specifically,
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 18 out of bounds for length 10
at SeniorResearch.Final_Project_Driver.bucketSort(Final_Project_Driver.java:349)
at SeniorResearch.Final_Project_Driver.main(Final_Project_Driver.java:218)
(I marked out the mentioned lines above)
Can anyone help me figure out why this is happening? What's changing from PRIME LOOP 1 to PRIME LOOP 2 that's causing an ArrayIndexOutOfBoundsException in the bucket sort and how do I fix it?
In your bucketSort method at you think you are using final int[] code = hash(input); to calculate the number of buckets, but in reality, you are calculating the hash of your array.
So what you have to do is calculate the number of different hash codes for your array elements.
Use the method which calculates the hash of a single integer, then count how many different hashes you've got, then add each integer into the "hash-bucket", and so on...

Twin array Find a Minimum value from each Array index must be different

You are given two arrays A and B each containing n, integers. You need to choose exactly one number from A and exactly one number from B such that the index of the two chosen numbers is not same and the sum of the 2 chosen values is minimum.
Your objective is to find and print this minimum value.
For example in the image shown below is the minimum sum.
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
static int twinArrays(int[] ar1, int[] ar2){
// Complete this function
int minAr1 = ar1[0];
int minAr2;
int index = 0;
for(int i =0; i<ar1.length;i++) {
if(ar1[i]<minAr1) {
minAr1 = ar1[i];
index = i;
}
}
if(index == 0) {
minAr2 = ar2[1];
}else {
minAr2 =ar2[0];
}
for(int j=0;j<ar2.length;j++) {
if(j!=index && minAr2>ar2[j]) {
minAr2 =ar2[j];
}
}
return minAr1+minAr2;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
if(n>=2 && n<=1000000) {
int[] ar1 = new int[n];
for(int ar1_i = 0; ar1_i < n; ar1_i++){
int temp1 = in.nextInt();
if(temp1>=1&&temp1<=1000000) {
ar1[ar1_i] = temp1;
}
}
int[] ar2 = new int[n];
for(int ar2_i = 0; ar2_i < n; ar2_i++){
int temp2 = in.nextInt();
if(temp2>=1&&temp2<=1000000) {
ar2[ar2_i] = temp2;
}
}
int result = twinArrays(ar1, ar2);
System.out.println(result);
}
}
}
i have Implemented that is working fine but still something is missing so some test case failing could anyone give me some clue and hint to optimize my code if you find any defect in this code
Your code works by finding the minimum value from the first array, then finding the minimum value from the second array that isn't at the same position of the minimum in the first array. The problem with this approach is that it isn't guaranteed to find the overall minimum sum. For example, consider these small arrays:
[0, 1], [0, 100]
Here, if you take the minimum value of the first array (0) and the minimum value of the second array that isn't at the same position (100), you get the sum 100. However, the correct sum to pick is the smallest value from the second array (0) and the second-smallest value from the first array (1) for a total of 1.
One observation that's useful here is that the minimum-sum pair must be one of the following:
The sum of the smallest values from each array.
The sum of the smallest value from one array and the second-smallest value from the other.
Your solution is on the right track here, except you don't consider taking the smallest from the second array and the second smallest from the first. Try editing your code to account for that case.
One simple observation is that if minimum elements from both arrays are at different position, Sum of both elements would be an answer so after sorting answer in this case would be A[0]+B[0], but if both are at the same position, there are two possibilities for answer after sorting both the arrays.
Suppose we have two arrays A and B which are sorted in increasing order. Then there are two possible answers and the actual answer would be minimum of them.
Take minimum possible number from array A so that number would be A[0] and now find the minimum possible number from array B such that index of that element is not equal to 0 so best possible choice would be B[1]. Therefore answer in this case is A[0]+B[1].
Another possibility is that we consider minimum possible number from array B first and then go to choose a number from array A so here those numbers would be A[1] and B[0] respectively and thus answer in this case is A[1]+B[0].
Now for the final answer, we can take minimum of both these possible answers.
Final_Answer = min(A[0]+B[1],A[1]+B[0]);
If you don't want to sort the Arrays due to tight time constraint. You can just keep track of First and Second minimum element of both arrays and use it in place of A[0],A[1] in above equation respectively.
A sample code using first and second minimum,
static int twinArrays(int[] ar1, int[] ar2){
int first_minimum_ar1 = Integer.MAX_VALUE;
int second_minimum_ar1 = Integer.MAX_VALUE;
int index_ar1=-1;
int first_minimum_ar2 = Integer.MAX_VALUE;
int second_minimum_ar2 = Integer.MAX_VALUE;
int index_ar2=-1;
for(int i=0;i<ar1.length;i++)
{
int element = ar1[i];
if(first_minimum_ar1>=element)
{
second_minimum_ar1=first_minimum_ar1;
first_minimum_ar1=element;
index_ar1=i;
}
else if(second_minimum_ar1>element)
{
second_minimum_ar1=element;
}
}
for(int i=0;i<ar2.length;i++)
{
int element = ar2[i];
if(first_minimum_ar2>=element)
{
second_minimum_ar2=first_minimum_ar2;
first_minimum_ar2=element;
index_ar2=i;
}
else if(second_minimum_ar2>element)
{
second_minimum_ar2=element;
}
}
if(index_ar2!=index_ar1)
return first_minimum_ar1+first_minimum_ar2;
return Math.min(first_minimum_ar1+second_minimum_ar2,first_minimum_ar2+second_minimum_ar1);
}
What I did was, sort one array(ar1) in ascending order(take ar[0]) and the other in descending order(ar2) and then take (ar2[ar2.length-1]).
class TwinArray{
static int twinArrays(int[] ar1, int[] ar2){
Arrays.sort(ar1);
Integer[] Ar2 = new Integer[ar2.length];
for (int i=0;i<ar2.length;i++)
Ar2[i]=ar2[i];
Arrays.sort(Ar2,Collections.reverseOrder());
System.out.println(Ar2[Ar2.length-1]);
return (ar1[0]+Ar2[Ar2.length-1]);
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] ar1 = new int[n];
for(int ar1_i = 0; ar1_i < n; ar1_i++){
ar1[ar1_i] = in.nextInt();
}
int[] ar2 = new int[n];
for(int ar2_i = 0; ar2_i < n; ar2_i++){
ar2[ar2_i] = in.nextInt();
}
int result = twinArrays(ar1, ar2);
System.out.println(result);
}
}
This one will probably pass all of your test cases.
Runtime Complexity ~ o(n)
static int twinArrays(int[] ar1, int[] ar2){
int ar1Minimum = Integer.MAX_VALUE , ar1MinIndex = -1;
int ar1SecondMin = Integer.MAX_VALUE ;
//Get the element with minimum value and index
for(int i = 0 ; i < ar1.length ; ++i){
if(ar1Minimum > ar1[i]){
ar1Minimum = ar1[i]; ar1MinIndex = i;
}
}
//Get the second minimum
for(int i = 0 ; i < ar1.length ; ++i){
if(ar1SecondMin > ar1[i] && i!=ar1MinIndex){ // i != ar1MinIndex = Important to avoid duplicate minimum values [1,1,2,4] min = 1 , secondMin = 2 and not 1
ar1SecondMin = ar1[i];
}
}
int ar2Minimum = Integer.MAX_VALUE , ar2MinIndex = -1;
int ar2SecondMin = Integer.MAX_VALUE ;
for(int i = 0 ; i < ar2.length ; ++i){
if(ar2Minimum > ar2[i]){
ar2Minimum = ar2[i]; ar2MinIndex = i;
}
}
for(int i = 0 ; i < ar2.length ; ++i){
if(ar2SecondMin > ar2[i] && i != ar2MinIndex){
ar2SecondMin = ar2[i];
}
}
if(ar1MinIndex != ar2MinIndex){
return ar1Minimum + ar2Minimum;
}
return Math.max((ar1Minimum + ar2SecondMin), (ar1SecondMin + ar2Minimum));
}

How to create int array containing (quasi) random values in a given range but with a fixed % of duplicates?

I am trying to create (in Java) an integer array containing a specified number of integers, k, (for example, 50, 500, 1000, etc.) that does not use library functions or Collections, but contains a random assortment of numbers in the range (i.e. from 1 to k), with a specified percentage of duplicates.
I have figured out how to implement the shuffle, but I am not sure how to best implement the dups threshold. What I have so far:
static void shuffle(int[] array) {
int n = array.length;
for (int i = 0; i < array.length; i++) {
// Get a random index of the array past i.
int random = i + (int) (Math.random() * (n - i));
// Swap the random element with the present element.
int randomElement = array[random];
array[random] = array[i];
array[i] = randomElement;
}
}
Then, using this method:
//Create an ascending ordered array of size k to be shuffled
int [] tempInit = new int [filesizes[i]];
for(int k = 0; k < filesizes[i]; k++)
{
tempInit[k] = k+1;
}
//Shuffle the ascending array
shuffle(tempInit);
for(int k = 0; k < tempInit.length; k++)
{
System.out.println(tempInit[k]);
}
One way I imagine it could work would be to use the percentage of duplicates required (let's say it's 20%) and then randomly select a fixed number of integers, and loop through the array and replace every element (if not equal to one of the fixed numbers) with one of these fixed numbers. I'm not sure what sort of logic would make sense to select these fixed numbers, or the amount of fixed numbers to use for replacement purposes.
Try this! For 80% for number 1 and 5% for each other up to 5:
Map<Double, Integer> map = new LinkedHashMap<>();
map.put(0.8, 1);
map.put(0.85, 2);
map.put(0.9, 3);
map.put(0.95, 4);
map.put(1, 5);
Random random = new Random();
double result = random.nextDouble();
int value = map.entrySet().stream().filter(entry -> entry.getKey() < result).reduce(0, Math::min);
edit: solved this as follows:
double percentDupes= 0.2;
//Create an ascending ordered array of size k to be shuffled
int [] tempSorted = new int [filesizes[i]];
for(int k = 0; k < filesizes[i]; k++)
{
tempSorted[k] = k+1;
}
//Shuffle the ascending array
shuffleArray(tempSorted);
//Figure out the proportion of the array to replace with duplicate values of elements already in the array
Double proportion = tempSorted.length*percentDupes;
int ratio = proportion.intValue();
//Instantiate a new array of size "ratio"
int [] tempShuffled = new int[ratio];
//Fill the new, smaller array with randomly selected elements from the original, sorted array
for(int b = 0; b< tempShuffled.length; b++)
{
int randNum = i + (int) (Math.random() * (tempSorted.length - i)); //Select a random element of the array to have as a duplicate
tempShuffled[b] = tempSorted[randNum]; //tempSorted was previously shuffled
}
//Shuffle this sub-array
shuffleArray(tempShuffled);
//Loop through (shuffled) original array and, if the values don't match, replace a non-dup with a dup value
for(int c= 0; c<tempShuffled.length; c++ )
{
if(tempSorted[c] != tempShuffled[c])
{
tempSorted[c] = tempShuffled[c];
}
}
//Final output to print to file
for(int k = 0; k < tempSorted.length; k++)
{
System.out.println(tempSorted[k]);
}

in Java, design linear algorithm that finds contiguous subsequence with highest sum

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.

Categories

Resources