I am trying to compare which has a greater quotient when multiplying adjacent elements:
public static void main(String args[]) {
int[] inputArray = {-5, 8, -9, 1, -5, 4};
int x = 0;
long maxsofar = 0;
while (x < inputArray.length - 1) {
int currentmax = inputArray[x] * inputArray[x + 1];
maxsofar = (maxsofar > currentmax) ? maxsofar : currentmax;
}
x++;
}
System.out.println(maxsofar);
}
So far my code works, but when I try to use negative integers on my array, it just outputs 0.
That's probably because 0 is > than negative numbers. All your adjacent elements when multiplied create negative numbers->
-5*8=-40
8*-9=-72
etc.
So 0 is the maximum one.
You can use Math.abs() for example to use the absolute value. Or you can set maxsofar to the Long.MIN_VALUE to get the largest number even if negative. The way you have done it you get the largest number > 0.
And also this way your program works for exactly that array (having 5 elemtents). A nicer way would be:
for (int i = 0; i < inputArray.length - 2; i++) {
int currentmax = inputArray[i] * inputArray[i + 1];
if (maxsofar < currentmax) {
maxsofar = currentmax;
} //No need to handle the case where you say A=A :)
}
Or even better you can do Math.max(maxsofar,currentmax);
Try using:
long maxsofar = Long.MIN_VALUE;
as initialization. Then the next max is guaranteed to be larger.
Related
Given an integer array, find the maximum number of sums of adjacent elements that are divisible by n.
Example 1:
input: long[] array = [1, 2, 3], n = 7
output: 0
Example 2:
input: long[] array = [1, 2, 4], n = 7
output: 1
Example 3:
input: long[] array = [2, 1, 2, 1, 1, 2, 1, 2], n = 4
output: 6
Constraints:
array.length = 50000
array[index] <= 2^31 - 1
n <= 2^31 - 1
Currently, this is my code:
public static int maxSums(long[] array, long n) {
int count = 0;
if (array.length == 1 && array[0] == n) {
return 1;
} else {
for (int i = 0; i < array.length; i++) {
long sum = 0;
for (int j = i; j < array.length; j++) {
sum += array[j];
if (sum % n == 0) {
count++;
}
}
}
}
return count;
}
which is essentially the window sliding technique. However, this code runs with time complexity O(n^2) which is pretty slow, and results in Apex CPU Time Limit Exceeded towards the higher end of the constraints. Is there a faster way to solve this?
An approach I just thought of is O(n*m), where n is the actual n parameter and m is the array length.
The algorithm remembers for every subsequence up to the current index what reminder the sequence sum has. This information is stored inside the array called currentMod.
When iterating over the input array this currentMod is updated. We simply add to each possible modulo value of iteration i-1 the value of the input array at index i. The updated array includes the number of subsequence sums ending at index i for each possible reminder: 0, 1, 2 up to n-1.
The element first element of tmpMod at index i includes the number of subsequences that end at index i and have a sum divisible by n. Therefore, we add them to our final result.
Here is the algorithm:
public static int maxSums(int[] array, int n) {
int[] currentMod = new int[n];
int count = 0;
for (int i = 0; i < array.length; i++) {
// Add +1 to 0 remainder as a new sequence can start at every index which has sum 0
currentMod[0] += 1;
int[] tmpMod = new int[n];
for (int j = 0; j < currentMod.length; j++) {
// For every subsequence reminder of i-1 calculate the reminders of adding element i to every subsequence
tmpMod[(j + array[i]) % n] += currentMod[j];
}
// Add number of subsequence sums that divide by n with remainder 0 to result
count += tmpMod[0];
currentMod = tmpMod;
}
return count;
}
P.S.: This algorithm is not strictly better/worse than yours. It depends on another input value. This means it depends on your inputs what is more efficient. My algorithm is only better for a case with large arrays and low n values.
EDIT: After a lot of thinking and testing I think I found a good solution. It is O(n) in time complexity. It is also O(n) in space complexity as there can be at most n different remainders with n values in the array.
The algorithm keeps track of the current remainder, which is dividable by the input n from the start. For each new subsequence, we add the 1 at the current remainder. In this way, we already define which total sum (mod n) we need that the subsequence is dividable by n.
public static int maxSums(int[] array, int n) {
Map<Integer, Integer> currentMod = new HashMap<Integer, Integer>();
int count = 0;
int currentZero = 0;
for (int val : array) {
currentMod.put(currentZero, currentMod.getOrDefault(currentZero, 0) + 1);
currentZero = (currentZero + val) % n;
count += currentMod.getOrDefault(currentZero, 0);
}
return count;
}
Also, some comparisons to show that it should work out:
len(array)=50000 and n=1000:
Your method: 11704 ms
My old one: 188 ms
My new one: 13 ms
len(array)=50000 and n=1000000:
Your method: 555 ms
My old one: stopped after 2 minutes
My new one: 6 ms
Is there a algorithm to determine a knapsack which has an exact weight W? I.e. it's like the normal 0/1 knapsack problem with n items each having weight w_i and value v_i. Maximise the value of all the items, however the total weight of the items in the knapsack need to have exactly weight W!
I know the "normal" 0/1 knapsack algorithm but this could also return a knapsack with less weight but higher value. I want to find the highest value but exact W weight.
Here is my 0/1 knapsack implementation:
public class KnapSackTest {
public static void main(String[] args) {
int[] w = new int[] {4, 1, 5, 8, 3, 9, 2}; //weights
int[] v = new int[] {2, 12, 8, 9, 3, 4, 3}; //values
int n = w.length;
int W = 15; // W (max weight)
int[][] DP = new int[n+1][W+1];
for(int i = 1; i < n+1; i++) {
for(int j = 0; j < W+1; j++) {
if(i == 0 || j == 0) {
DP[i][j] = 0;
} else if (j - w[i-1] >= 0) {
DP[i][j] = Math.max(DP[i-1][j], DP[i-1][j - w[i-1]] + v[i-1]);
} else {
DP[i][j] = DP[i-1][j];
}
}
}
System.out.println("Result: " + DP[n][W]);
}
}
This gives me:
Result: 29
(Just ask if anything is unclear in my question!)
Actually, the accepted answer is wrong, as found by #Shinchan in the comments.
You get exact weight knapsack by changing only the initial dp state, not the algorithm itself.
The initialization, instead of:
if(i == 0 || j == 0) {
DP[i][j] = 0;
}
should be:
if (j == 0) {
DP[i][j] = 0;
} else if (i == 0 && j > 0) { // obviously `&& j > 0` is not needed, but for clarity
DP[i][j] = -inf;
}
The rest stays as in your question.
By simply setting DP[i][j] = -infinity in your last else clause it will do the trick.
The ides behind it is to slightly change the recursive formula definition to calculate:
Find the maximal value with exactly weight j up to item i.
Now, the induction hypothesis will change, and the proof of correctness will be very similar to regular knapsack with the following modification:
DP[i][j-weight[i]] is now the maximal value that can be constructed with exactly j-weight[i], and you can either take item i, giving value of DP[i][j-weight[i]], or not taking it, giving value of DP[i-1][j] - which is the maximal value when using exactly weight j with first i-1 items.
Note that if for some reason you cannot construct DP[i][j], you will never use it, as the value -infinity will always discarded when looking for MAX.
Here is what I got so far
public static int[] firstPrimeNumbers(int n) {
int[] k = new int[n];
int m = 0;
for (int i = 0; i < n; i++) {
if (isPrime(i)) {
k[m] = i;
m++;
}
}
return k;
}
Problem is, when I try to print the resulting array, I get a bunch of 0's at the end. For example when I took n = 10, the program printed
2, 3, 5, 7, 0, 0, 0, 0, 0, 0
Hows that even possible? What am I doing wrong?
What happens here is fairly easy.
k has size 10 and initially filled with zeros.
Then you check the first 10 natural numbers and check whether they are prime.
So for each non-prime number you should get a 0
Maybe replace i<n by m<n but that depends a bit on what you want to achieve.
You should modify your for loop. What you are doing is actually returning in an array of n elements the primitive numbers less than n
public static int[] firstPrimeNumbers(int n) {
int[] k = new int[n];
int nr = 2;
int m = 0;
while(m<n){
if(isPrime(nr)){
k[m] = nr;
m++;
}
nr++;
}
return k;
}
You are just counting until i == n (so only looking at number up to n) - you need to keep incrementing i until m == n so you are considering whether numbers > n are prime.
If you used better variable names like nextPrimeIndex or primesFound instead of m this would probably be easier to spot.
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.
I'm writing this Java program that finds all the prime numbers between a given range. Because I'm dealing with really big numbers my code seems to be not fast enough and gives me a time error. Here is my code, does anyone know to make it faster? Thanks.
import java.util.*;
public class primes2
{
private static Scanner streamReader = new Scanner(System.in);
public static void main(String[] args)
{
int xrange = streamReader.nextInt();
int zrange = streamReader.nextInt();
for (int checks = xrange; checks <= zrange; checks++)
{
boolean[] checkForPrime = Primes(1000000);
if (checkForPrime[checks])
{
System.out.println(checks);
}
}
}
public static boolean[] Primes(int n)
{
boolean[] isPrime = new boolean[n + 1];
if (n >= 2)
isPrime[2] = true;
for (int i = 3; i <= n; i += 2)
isPrime[i] = true;
for (int i = 3, end = sqrt(n); i <= end; i += 2)
{
if (isPrime[i])
{
for (int j = i * 3; j <= n; j += i << 1)
isPrime[j] = false;
}
}
return isPrime;
}
public static int sqrt(int x)
{
int y = 0;
for (int i = 15; i >= 0; i--)
{
y |= 1 << i;
if (y > 46340 || y * y > x)
y ^= 1 << i;
}
return y;
}
}
You'll get an enormous improvement just by changing this:
for (int checks = xrange; checks <= zrange; checks++)
{
boolean[] checkForPrime = Primes(1000000);
to this:
boolean[] checkForPrime = Primes(1000000);
for (int checks = xrange; checks <= zrange; checks++)
{
Your current code regenerates the sieve zrange - xrange + 1 times, but you actually only need to generate it once.
The obvious problem is that you're computing the primes up to 1000000 many time (zrange - xrange times). Another is that you dont need to compute the primes up to 1000000, you just need to check to primes up to zrange, so you're wasting time when zrange < 1000000, and getting a buffer overflow when zrange > 1000000.
You can start your inner loop from i*i, i.e. instead of for (int j = i * 3; j <= n; j += i << 1) you can write for (int j = i * i; j <= n; j += i << 1) for a minor speed-up.
Also, you have to be sure that your zrange is not greater than 1000000.
If xrange is much greater than sqrt(zrange), you can also split your sieve array in two, for an offset sieve scheme. The lower array will span from 2 to sqrt(zrange). The upper one will span from xrange to zrange. As you sieve your lower array, as each new prime becomes identified by it, inside your inner loop, in addition to marking the lower array up to its end also sieve the upper array. You will have to calcuate the starting offset for each prime i, and use the same step of 2*i as you do for the lower half. If your range is wider than a few primes, you will get speed advantage (otherwise just trial division by odds will suffice).
Another thing to try is, if evens > 2 are not primes anyway, why represent them in the array and waste half of the space? You can treat each i as representing an odd number, 2*i+1, thus compressing your array in half.
Last simple trick is to eliminate the multiples of 3 in advance as well, by marking ON not just odds (i.e. coprimes with 2), by { ... i+=2; ...}, but only coprimes with 2 and 3, by { ... i+=2; ... i+=4; ... } instead. Also, when marking OFF multiples of primes > 3, use { ... j+=2*i; ... j+=4i; ...} too. E.g., in 5*5, 5*7, 5*9, 5*11, ... you don't need to mark OFF 5*9, if no multiple of 3 was marked ON in the first place.