is it a Heap Max? [duplicate] - java

This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 4 years ago.
For a project, am i working with heaps. In this project i have to "investigate" whether an array is a max heap.
These 2 rules apply for a max heap:
The parent shall be bigger or equal to its child / children
Each node, in a heap, shall contain an element
Therefore have i created 2 for loops checking whether these rules apply. Unfortunately for me, my code doesn't work.
I have 2 for loops:
//Checks if there's a 0 value in the array. If so: Return false
for (int i = 1; i <= A.length; i++) {
System.out.println("A.length: " + A[i]);
if (A[i] == 0) {
System.out.println("weweh: "+ A[i]);
return false;
}
//Checks if either left or right child have a bigger value than itself
for (int i = 1; i <= (A.length - 2) / 2; i++) {
System.out.println("A: " + i);
if (A[i] < A[2 * i] || A[i] < A[2 * i + 1]) {
return false;
}
}
//the array
int A[] = {0, 40, 35, 30, 25, 15, 10, 5};
The last for loop works, but for some reason i get a mistake in the first for loop. The loop can find a number. Lets say that i picked 15 to be equal with A[i], then it would work and return false, but when the selected number 0 isn't there, then it sends me the error, and it wont go further for the second loop.
//Error:
A.length: 40
A.length: 35
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 8
A.length: 30
A.length: 25
A.length: 15
A.length: 10
A.length: 5
at ismaxheap.IsMaxHeap.MaxHeap(IsMaxHeap.java:24)
at ismaxheap.IsMaxHeap.main(IsMaxHeap.java:15)
/Users/yusuf/Library/Caches/NetBeans/8.2/executor-snippets/run.xml:53: Java returned: 1
BUILD FAILED (total time: 0 seconds)
THE WHOLE CODE:
public class IsMaxHeap {
public static void main(String[] args) {
MaxHeap();
System.out.println("Max Heap: " + MaxHeap());
}
public static boolean MaxHeap() {
int A[] = {0, 40, 35, 30, 25, 15, 10, 5};
for (int i = 1; i <= A.length; i++) {
System.out.println("A.length: " + A[i]);
if (A[i] == 0) {
System.out.println("weweh: "+ A[i]);
return false;
}
}
for (int i = 1; i <= (A.length - 2) / 2; i++) {
System.out.println("A: " + i);
if (A[i] < A[2 * i] || A[i] < A[2 * i + 1]) {
return false;
}
}
return true;
}
}

In your first loop you are looping one more than possible by using <=
for (int i = 1; i <= A.length; i++)
Since you are trying to access A[i] and if i == A.length then you are out of bounds.
Should be:
for (int i = 1; i < A.length; i++)
Now I don't know why are you starting at index 1 since indexing in Java start with 0.
Dealing with special case of one child
This is the case when you array length is 3 (Since the zero index is ignored)
All you have to check is if A[2] < A[1] to be a Max heap, otherwise return false immediately.
Otherwise do the normal loop.

Related

Write a function that returns the maximum quantity of non-zero elements between two zero elements

Given an array of integers I need to find the maximum quantity of non zero elements between two zero elements
For example: int[] arr = {1,2,0,2,3,4,5,0,1,2,3,4,5,6,7,8,8,0,1}
This should return 9. However, this returns 4:
static int solution(int[] arr) {
int count = 0;
int maxCount = 0;
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] == 0 && i < arr.length - 2) {
i++;
while (arr[i] != 0) {
count++;
i++;
}
maxCount = count;
}
}
return maxCount;
}
UPD: For the case of {1,2,3,0,0,3,2,1}, function should return 0
Some issues:
The inner loop may run i out of the array's range.
When you find the ending zero, your code does not take into account that this zero is also the start of a new group, and "misses" it.
count is never reset to zero, so it keeps increasing also when you get into a second "group"
maxCount is set unconditionally, yet it should only be updated if the new count is greater than the count you already got.
There is no provision for when there is no group at all. I would suggest to return -1 in that case, so to differentiate it from the case where there is a group of length 0. This -1 should then be the initial value of the counts.
Also:
It is strange that the outer loop condition is made more strict by the if condition at the top of your loop. So why not make that i< arr.length-2 the loop condition?
Here is a correction of your attempt:
static int solution(int[] arr) {
int count = -1; // Start with invalid count
int maxCount = -1;
for (int i = 0; i < arr.length - 2; i++) { // Stricter loop condition
if (arr[i] == 0) {
count = 0; // Reset counter
// Safety & Look ahead for zero
while (i + 1 < arr.length && arr[i + 1] != 0) {
count++;
i++;
}
if (i + 1 >= arr.length) break; // No ending zero found
// Only update if improvement
if (count > maxCount) maxCount = count;
}
}
return maxCount;
}
You can however reduce the code a bit by using the outer loop to do the job of the inner loop:
static int solution(int[] arr) {
// Start with a count that can safely increment with `++` without getting positive
int count = -arr.length;
int maxCount = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
if (count > maxCount) maxCount = count;
count = 0; // Start of a potential new group
} else {
count++;
}
}
return maxCount;
}
And instead of maintaining count you could maintain the last starting index of a group:
static int solution(int[] arr) {
int start = arr.length; // Invalid start index
int maxCount = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
if (i - start > maxCount) maxCount = i - start;
start = i + 1;
}
}
}
This problem can be solved in a single pass. Observe the counts of non-zero elements when progressing from left to right:
1,2,0,2,3,4,5,0,1,2,3,4,5,6,7,8,8,0,1
- - 0 1 2 3 4 0 1 2 3 4 5 6 7 8 9 0 1
Now consider the partial solution for the left subarray processed
1,2,0,2,3,4,5,0,1,2,3,4,5,6,7,8,8,0,1
- - 0 1 2 3 4 0 1 2 3 4 5 6 7 8 9 0 1
0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 9 9
This tells you how to solve:
keep a counter of the number of non-zero elements since the previous zero. (Increment on nonzero, reset to zero on zero.)
keep the "answer" updated: every time you see a zero, keep the largest of the counter and the current answer, initially zero.
For the initial elements, it suffices to keep the count negative so that it does not influence the answer. A safe option is to initialize with minus the length of the list.
Technically, the loop is based on an invariant expressing that the counter holds the number of numbers since the previous zero (or a negative value), while answer holds the correct answer for the subarray traversed so far.
counter= - length(list)
answer= 0
for element in list:
if element == 0:
answer= max(counter, answer)
counter= 0
else:
counter= counter + 1
This will fix your all scenario,
Time complexity is O(n)
public static int maxCountBwZero(int arr[]) {
int i = 0;
int tempCount = 0;
int size = arr.length;
int maxCount = 0;
boolean startCount = false;
while (i < size) {
if (arr[i] == 0) {
if (maxCount == 0 && tempCount == 0) {
startCount = true;
} else {
if (tempCount > 0 && (tempCount >= maxCount)) {
maxCount = tempCount;
}
tempCount = 0;
}
} else if (startCount) {
tempCount++;
}
i++;
}
return maxCount;
}
public static void main(String[] args) {
int[] arr = { 1, 2, 0, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 0, 1 };
int[] arr1 = { 1, 2, 3, 0, 0, 3, 2, 1 };
System.out.println(maxCountBwZero(arr));
System.out.println(maxCountBwZero(arr1));
}

How to go through a 2d array with two pointers?

I'm told to implement two pointers which will run through the first and last index of my array and try to find a pair that returns 20.
If the pair's sum is larger than 20 then lower the last index by 1 and if the pair's sum is smaller than 20 then add the first index by 1. If the pair returns 20 find the smallest number's index.
This is my checkSum method:
public static int checkSum(int[] array){
// This function will inspect the input to find any pair of values that add up to 20
// if it finds such a pair, it will return the *index* of the smallest value
// if it does not find such as pair, it will return -1;
int twenty = 20;
int zero = 0;
int checkIndex = array.length;
for (int i = 0; i < array.length - 1; i++){
for (int k = array.length - 1; k < array.length; k++){
if (array[i] + array[k] == twenty){
// 0 + 1
System.out.println("this print out 20");
System.out.println(array [k] + " + " + array[i]);
if (array [k] >= array [zero]){
//need to print out the index of the minimum value
checkIndex = zero;
}
}
else if (array[i] + array[k] > twenty){
array[k]--;
checkIndex = array[k];
}
else if (array[i] + array[k] < twenty){
//tried a different method to see if it would increment the index rather than the value
array[i+1] = array[i];
checkIndex = array[i];
}
}
}// remove the following line after you are done writing the function
System.out.println(checkIndex);
return checkIndex;
}
and this is the main method that is provided:
public static void main(String[] args) {
int[] array1 = new int[]{5, 7, 8, 9, 10, 15, 16};
if (checkSum(array1) != 0){
System.err.println("TEST1 FAILED");
}
int[] array2 = new int[]{3, 5, 8, 9, 10, 15, 16};
if (checkSum(array2) != 1){
System.err.println("TEST2 FAILED");
}
int[] array3 = new int[]{3, 4, 6, 9, 10, 14, 15};
if (checkSum(array3) != 2){
System.err.println("TEST3 FAILED");
}
int[] array4 = new int[]{6, 7, 8, 9, 10, 15, 16};
if (checkSum(array4) != -1){
System.err.println("TEST4 FAILED");
}
System.out.println("Done!!!");
}
My error is that it's doing:
Lets say array[i] + array[k] > twenty:
expected output:
array[0] + array[6] = 5 + 16 > 20
so do array[0] + array[5] = 5 + 15 = 20
than notice that 5 < 15 so the index is 0.
current output:
array[6] + array [6] - 1 = 16 + 15 > 20
so array[6] - 1 + array [6] - 1 - 1 = 15 + 14 > 20
and so forth...
You don't need a nested loop to do the task. Assuming your input array is always sorted, you can declare two variables in one for loop one starting at the first element of your array and the second at the last element. Check at each step if the sum equals 20 if yes find the index and break the loop, if not increment your first variable or decrement your second variable depending on whether the sum was greater or less than 20.
public static int checkSum(int[] array) {
int checkIndex = -1;
int first = 0;
int last = array.length -1;
for (int i = first, k = last; i < k; ) {
if (array[i] + array[k] == 20){
System.out.println("Found a pair which adds up to 20");
System.out.println(array [i] + " + " + array[k]);
//find index of smallest value
if (array[i] < array[k]){
checkIndex = i;
}
else {
checkIndex = k;
}
//break out of loop if found a valid pair
break;
}
else {
//you will get here if the sum was not 20. Increment i or decrement k according to sum > 20 0r sum < 20
if (array[i] + array[k] > 20){
k--;
}
else {
i++;
}
}
}
System.out.println("index to return" + checkIndex);
return checkIndex;
}

ArrayIndexOutOfBoundsException: [duplicate]

This question already has answers here:
How can I avoid ArrayIndexOutOfBoundsException or IndexOutOfBoundsException? [duplicate]
(2 answers)
Closed 7 years ago.
Help me to solve this error. This code is for Gutherine series.Consider the following algorithm
Start with a positive number n
if n is even then divide by 2
if n is odd then multiply by 3 and add 1
continue this until n becomes 1
public class Gutherine {
public static void main(String[] args) {
int a[] = {8, 3,2, 1};
int result = isGutherineSequence(a);
System.out.println(result);
}
public static int isGutherineSequence(int a[]) {
int i = 0;
int t = 0;
for (i = 0; i < 4; i++) {
if (a[i] % 2 == 0) {
if (a[i + 1] == a[i] / 2) {
t++;
}
} else if (a[i + 1] == a[i] * 3 + 1) {
t++;
}
}
if (t == 3) {
return 1;
} else {
return 0;
}
}
}
Since inside your loop you access a[i+1], you should iterate i until the next to last element, so change
for (i = 0; i < 4; i++)
to
for (i = 0; i < a.length - 1; i++)
BTW, you don't need the t counter. Once you discover that the series is not a Gutherine sequence, you can return false. You also fail to check that the last element is 1. And you should return a boolean instead of 0 or 1.
Here's a suggested implementation :
public static boolean isGutherineSequence(int a[]) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] % 2 == 0) {
if (a[i + 1] != a[i] / 2) {
return false;
}
} else if (a[i + 1] != a[i] * 3 + 1) {
return false;
}
}
return (a[a.length - 1] == 1);
}
The exception is caused by your referring to
a[i + 1]
If a[i] could be any element of the array, a[i + 1] could be one to the right of the rightmost element. So your array index would be out of bounds in that case.
The out-of-bounds exception results from your the indirection a[i + 1] even when i is odd. The loop in your isGutherineSequence function will let i reach 3 and the offending line
} else if (a[i + 1] == a[i] * 3 + 1) {
Will effectively try to extract a non-existent a[4].
You should either stop the loop at a previous spot or provide an alternate test for the last element.

How do I generate Primes Using 6*k +- 1 rule

We know that all primes above 3 can be generated using:
6 * k + 1
6 * k - 1
However we all numbers generated from the above formulas are not prime.
For Example:
6 * 6 - 1 = 35 which is clearly divisible by 5.
To Eliminate such conditions, I used a Sieve Method and removing the numbers which are factors of the numbers generated from the above formula.
Using the facts:
A number is said to be prime if it has no prime factors.
As we can generate all the prime numbers using the above formulas.
If we can remove all the multiples of the above numbers we are left with only prime numbers.
To generate primes below 1000.
ArrayList<Integer> primes = new ArrayList<>();
primes.add(2);//explicitly add
primes.add(3);//2 and 3
int n = 1000;
for (int i = 1; i <= (n / 6) ; i++) {
//get all the numbers which can be generated by the formula
int prod6k = 6 * i;
primes.add(prod6k - 1);
primes.add(prod6k + 1);
}
for (int i = 0; i < primes.size(); i++) {
int k = primes.get(i);
//remove all the factors of the numbers generated by the formula
for(int j = k * k; j <= n; j += k)//changed to k * k from 2 * k, Thanks to DTing
{
int index = primes.indexOf(j);
if(index != -1)
primes.remove(index);
}
}
System.out.println(primes);
However, this method does generate the prime numbers correctly. This runs in a much faster way as we need not check for all the numbers which we do check in a Sieve.
My question is that am I missing any edge case? This would be a lot better but I never saw someone using this. Am I doing something wrong?
Can this approach be much more optimized?
Taking a boolean[] instead of an ArrayList is much faster.
int n = 100000000;
boolean[] primes = new boolean[n + 1];
for (int i = 0; i <= n; i++)
primes[i] = false;
primes[2] = primes[3] = true;
for (int i = 1; i <= n / 6; i++) {
int prod6k = 6 * i;
primes[prod6k + 1] = true;
primes[prod6k - 1] = true;
}
for (int i = 0; i <= n; i++) {
if (primes[i]) {
int k = i;
for (int j = k * k; j <= n && j > 0; j += k) {
primes[j] = false;
}
}
}
for (int i = 0; i <= n; i++)
if (primes[i])
System.out.print(i + " ");
5 is the first number generated by your criteria. Let's take a look at the numbers generated up to 25:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
Now, let's look at these same numbers, when we use the Sieve of Eratosthenes algorithm:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
After removing 2:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
After removing 3:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
This is the same as the first set! Notice they both include 25, which is not prime. If we think about it, this is an obvious result. Consider any group of 6 consecutive numbers:
6k - 3, 6k - 2, 6k - 1, 6k, 6k + 1, 6k + 2
If we factor a little, we get:
3*(2k - 1), 2*(3k - 1), 6k - 1, 6*(k), 6k + 1, 2*(3k + 1)
In any group of 6 consecutive numbers, three of them will be divisible by two, and two of them will be divisible by three. These are exactly the numbers we have removed so far! Therefore:
Your algorithm to only use 6k - 1 and 6k + 1 is exactly the same as the first two rounds of the Sieve of Erathosthenes.
It's a pretty nice speed improvement over the Sieve, too, because we don't have to add all those extra elements just to remove them. This explains why your algorithm works and why it doesn't miss any cases; because it's exactly the same as the Sieve.
Anyway, I agree that once you've generated primes, your boolean way is by far the fastest. I have set up a benchmark using your ArrayList way, your boolean[] way, and my own way using LinkedList and iterator.remove() (because removals are fast in a LinkedList. Here's the code for my test harness. Note that I run the test 12 times to ensure that the JVM is warmed up, and I print the size of the list and change the size of n to attempt to prevent too much branch prediction optimization. You can also get faster in all three methods by using += 6 in the initial seed, instead of prod6k:
import java.util.*;
public class PrimeGenerator {
public static List<Integer> generatePrimesArrayList(int n) {
List<Integer> primes = new ArrayList<>(getApproximateSize(n));
primes.add(2);// explicitly add
primes.add(3);// 2 and 3
for (int i = 6; i <= n; i+=6) {
// get all the numbers which can be generated by the formula
primes.add(i - 1);
primes.add(i + 1);
}
for (int i = 0; i < primes.size(); i++) {
int k = primes.get(i);
// remove all the factors of the numbers generated by the formula
for (int j = k * k; j <= n; j += k)// changed to k * k from 2 * k, Thanks
// to DTing
{
int index = primes.indexOf(j);
if (index != -1)
primes.remove(index);
}
}
return primes;
}
public static List<Integer> generatePrimesBoolean(int n) {
boolean[] primes = new boolean[n + 5];
for (int i = 0; i <= n; i++)
primes[i] = false;
primes[2] = primes[3] = true;
for (int i = 6; i <= n; i+=6) {
primes[i + 1] = true;
primes[i - 1] = true;
}
for (int i = 0; i <= n; i++) {
if (primes[i]) {
int k = i;
for (int j = k * k; j <= n && j > 0; j += k) {
primes[j] = false;
}
}
}
int approximateSize = getApproximateSize(n);
List<Integer> primesList = new ArrayList<>(approximateSize);
for (int i = 0; i <= n; i++)
if (primes[i])
primesList.add(i);
return primesList;
}
private static int getApproximateSize(int n) {
// Prime Number Theorem. Round up
int approximateSize = (int) Math.ceil(((double) n) / (Math.log(n)));
return approximateSize;
}
public static List<Integer> generatePrimesLinkedList(int n) {
List<Integer> primes = new LinkedList<>();
primes.add(2);// explicitly add
primes.add(3);// 2 and 3
for (int i = 6; i <= n; i+=6) {
// get all the numbers which can be generated by the formula
primes.add(i - 1);
primes.add(i + 1);
}
for (int i = 0; i < primes.size(); i++) {
int k = primes.get(i);
for (Iterator<Integer> iterator = primes.iterator(); iterator.hasNext();) {
int primeCandidate = iterator.next();
if (primeCandidate == k)
continue; // Always skip yourself
if (primeCandidate == (primeCandidate / k) * k)
iterator.remove();
}
}
return primes;
}
public static void main(String... args) {
int initial = 4000;
for (int i = 0; i < 12; i++) {
int n = initial * i;
long start = System.currentTimeMillis();
List<Integer> result = generatePrimesArrayList(n);
long seconds = System.currentTimeMillis() - start;
System.out.println(result.size() + "\tArrayList Seconds: " + seconds);
start = System.currentTimeMillis();
result = generatePrimesBoolean(n);
seconds = System.currentTimeMillis() - start;
System.out.println(result.size() + "\tBoolean Seconds: " + seconds);
start = System.currentTimeMillis();
result = generatePrimesLinkedList(n);
seconds = System.currentTimeMillis() - start;
System.out.println(result.size() + "\tLinkedList Seconds: " + seconds);
}
}
}
And the results of the last few trials:
3432 ArrayList Seconds: 430
3432 Boolean Seconds: 0
3432 LinkedList Seconds: 90
3825 ArrayList Seconds: 538
3824 Boolean Seconds: 0
3824 LinkedList Seconds: 81
4203 ArrayList Seconds: 681
4203 Boolean Seconds: 0
4203 LinkedList Seconds: 100
4579 ArrayList Seconds: 840
4579 Boolean Seconds: 0
4579 LinkedList Seconds: 111
You don't need to add all possible candidates to the array. You can create a Set to store all non primes.
Also you can start checking at k * k, rather than 2 * k
public void primesTo1000() {
Set<Integer> notPrimes = new HashSet<>();
ArrayList<Integer> primes = new ArrayList<>();
primes.add(2);//explicitly add
primes.add(3);//2 and 3
for (int i = 1; i < (1000 / 6); i++) {
handlePossiblePrime(6 * i - 1, primes, notPrimes);
handlePossiblePrime(6 * i + 1, primes, notPrimes);
}
System.out.println(primes);
}
public void handlePossiblePrime(
int k, List<Integer> primes, Set<Integer> notPrimes) {
if (!notPrimes.contains(k)) {
primes.add(k);
for (int j = k * k; j <= 1000; j += k) {
notPrimes.add(j);
}
}
}
untested code, check corners
Here is a bit packing version of the sieve as suggested in the answer referenced by #Will Ness. Rather than return the nth prime, this version returns a list of primes to n:
public List<Integer> primesTo(int n) {
List<Integer> primes = new ArrayList<>();
if (n > 1) {
int limit = (n - 3) >> 1;
int[] sieve = new int[(limit >> 5) + 1];
for (int i = 0; i <= (int) (Math.sqrt(n) - 3) >> 1; i++)
if ((sieve[i >> 5] & (1 << (i & 31))) == 0) {
int p = i + i + 3;
for (int j = (p * p - 3) >> 1; j <= limit; j += p)
sieve[j >> 5] |= 1 << (j & 31);
}
primes.add(2);
for (int i = 0; i <= limit; i++)
if ((sieve[i >> 5] & (1 << (i & 31))) == 0)
primes.add(i + i + 3);
}
return primes;
}
There seems to be a bug in your updated code that uses a boolean array (it is not returning all the primes).
public static List<Integer> booleanSieve(int n) {
boolean[] primes = new boolean[n + 5];
for (int i = 0; i <= n; i++)
primes[i] = false;
primes[2] = primes[3] = true;
for (int i = 1; i <= n / 6; i++) {
int prod6k = 6 * i;
primes[prod6k + 1] = true;
primes[prod6k - 1] = true;
}
for (int i = 0; i <= n; i++) {
if (primes[i]) {
int k = i;
for (int j = k * k; j <= n && j > 0; j += k) {
primes[j] = false;
}
}
}
List<Integer> primesList = new ArrayList<>();
for (int i = 0; i <= n; i++)
if (primes[i])
primesList.add(i);
return primesList;
}
public static List<Integer> bitPacking(int n) {
List<Integer> primes = new ArrayList<>();
if (n > 1) {
int limit = (n - 3) >> 1;
int[] sieve = new int[(limit >> 5) + 1];
for (int i = 0; i <= (int) (Math.sqrt(n) - 3) >> 1; i++)
if ((sieve[i >> 5] & (1 << (i & 31))) == 0) {
int p = i + i + 3;
for (int j = (p * p - 3) >> 1; j <= limit; j += p)
sieve[j >> 5] |= 1 << (j & 31);
}
primes.add(2);
for (int i = 0; i <= limit; i++)
if ((sieve[i >> 5] & (1 << (i & 31))) == 0)
primes.add(i + i + 3);
}
return primes;
}
public static void main(String... args) {
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
for (int i = 0; i < 10; i++) {
int n = (int) Math.pow(10, i);
Stopwatch timer = Stopwatch.createUnstarted();
timer.start();
List<Integer> result = booleanSieve(n);
timer.stop();
System.out.println(result.size() + "\tBoolean: " + timer);
}
for (int i = 0; i < 10; i++) {
int n = (int) Math.pow(10, i);
Stopwatch timer = Stopwatch.createUnstarted();
timer.start();
List<Integer> result = bitPacking(n);
timer.stop();
System.out.println(result.size() + "\tBitPacking: " + timer);
}
});
}
0 Boolean: 38.51 μs
4 Boolean: 45.77 μs
25 Boolean: 31.56 μs
168 Boolean: 227.1 μs
1229 Boolean: 1.395 ms
9592 Boolean: 4.289 ms
78491 Boolean: 25.96 ms
664116 Boolean: 133.5 ms
5717622 Boolean: 3.216 s
46707218 Boolean: 32.18 s
0 BitPacking: 117.0 μs
4 BitPacking: 11.25 μs
25 BitPacking: 11.53 μs
168 BitPacking: 70.03 μs
1229 BitPacking: 471.8 μs
9592 BitPacking: 3.701 ms
78498 BitPacking: 9.651 ms
664579 BitPacking: 43.43 ms
5761455 BitPacking: 1.483 s
50847534 BitPacking: 17.71 s
There are several things that could be optimized.
For starters, the "contains" and "removeAll" operations on an ArrayList are rather expensive operations (linear for the former, worst case quadratic for the latter) so you might not want to use the ArrayList for this. A Hash- or TreeSet has better complexities for this, being nearly constant (Hashing complexities are weird) and logarithmic I think
You could look into the sieve of sieve of Eratosthenes if you want a more efficient sieve altogeter, but that would be besides the point of your question about the 6k +-1 trick. It is slightly but not noticably more memory expensive than your solution, but way faster.
Can this approach be much more optimized?
The answer is yes.
I'll start by saying that it is a good idea to use the sieve on a subset of number within a certain range, and your suggesting is doing exactly that.
Reading about generating Primes:
...Furthermore, based on the sieve formalisms, some integer sequences
(sequence A240673 in OEIS) are constructed which they also could be used for generating primes in certain intervals.
The meaning of this paragraph is that your approach of starting with a reduced list of integers was indeed adopted by the academy, but their techniques are more efficient (but also, naturally, more complex).
You can generate your trial numbers with a wheel, adding 2 and 4 alternately, that eliminates the multiplication in 6 * k +/- 1.
public void primesTo1000() {
Set<Integer> notPrimes = new HashSet<>();
ArrayList<Integer> primes = new ArrayList<>();
primes.add(2); //explicitly add
primes.add(3); //2 and 3
int step = 2;
int num = 5 // 2 and 3 already handled.
while (num < 1000) {
handlePossiblePrime(num, primes, notPrimes);
num += step; // Step to next number.
step = 6 - step; // Step by 2, 4 alternately.
}
System.out.println(primes);
}
Probably the most suitable standard datastructure for Sieve of Eratosthenes is the BitSet. Here's my solution:
static BitSet genPrimes(int n) {
BitSet primes = new BitSet(n);
primes.set(2); // add 2 explicitly
primes.set(3); // add 3 explicitly
for (int i = 6; i <= n ; i += 6) { // step by 6 instead of multiplication
primes.set(i - 1);
primes.set(i + 1);
}
int max = (int) Math.sqrt(n); // don't need to filter multiples of primes bigger than max
// this for loop enumerates all set bits starting from 5 till the max
// sieving 2 and 3 is meaningless: n*6+1 and n*6-1 are never divisible by 2 or 3
for (int i = primes.nextSetBit(5); i >= 0 && i <= max; i = primes.nextSetBit(i+1)) {
// The actual sieve algorithm like in your code
for(int j = i * i; j <= n; j += i)
primes.clear(j);
}
return primes;
}
Usage:
BitSet primes = genPrimes(1000); // generate primes up to 1000
System.out.println(primes.cardinality()); // print number of primes
// print all primes like {2, 3, 5, ...}
System.out.println(primes);
// print all primes one per line
for(int prime = primes.nextSetBit(0); prime >= 0; prime = primes.nextSetBit(prime+1))
System.out.println(prime);
// print all primes one per line using java 8:
primes.stream().forEach(System.out::println);
The boolean-based version may work faster for small n values, but if you need, for example, a million of prime numbers, BitSet will outperform it in several times and actually works correctly. Here's lame benchmark:
public static void main(String... args) {
long start = System.nanoTime();
BitSet res = genPrimes(10000000);
long diff = System.nanoTime() - start;
System.out.println(res.cardinality() + "\tBitSet Seconds: " + diff / 1e9);
start = System.nanoTime();
List<Integer> result = generatePrimesBoolean(10000000); // from durron597 answer
diff = System.nanoTime() - start;
System.out.println(result.size() + "\tBoolean Seconds: " + diff / 1e9);
}
Output:
664579 BitSet Seconds: 0.065987717
664116 Boolean Seconds: 0.167620323
664579 is the correct number of primes below 10000000.
This method below shows how to find prime nos using 6k+/-1 logic
this was written in python 3.6
def isPrime(n):
if(n<=1):
return 0
elif(n<4): #2 , 3 are prime
return 1
elif(n%2==0): #already excluded no.2 ,so any no. div. by 2 cant be prime
return 0
elif(n<9): #5, 7 are prime and 6,8 are excl. in the above step
return 1
elif(n%3==0):
return 1
f=5 #Till now we have checked the div. of n with 2,3 which means with 4,6,8 also now that is why f=5
r=int(n**.5) #rounding of root n, i.e: floor(sqrt(n)) r*r<=n
while(f<=r):
if(n%f==0): #checking if n has any primefactor lessthan sqrt(n), refer LINE 1
return 0
if(n%(f+2)==0): #remember her we are not incrementing f, see the 6k+1 rule to understand this while loop steps ,you will see that most values of f are prime
return 0
f=f+6
return 1
def prime_nos():
counter=2 #we know 2,3 are prime
print(2)
print(3) #we know 2,3 are prime
i=1
s=5 #sum 2+3
t=0
n=int(input("Enter the upper limit( should be > 3: "))
n=(n-1)//6 #finding max. limit(n=6*i+1) upto which I(here n on left hand side) should run
while(i<n):#2*(10**6)):
if (isPrime(6*i-1)):
counter=counter+1
print(6*i-1) #prime no
if(isPrime(6*i+1)):
counter=counter+1
print(6*i+1) #prime no
i+=1
prime_nos() #fn. call
Your prime number formula mathematically incorrect ex. take 96 it dividable to 6 96/6=16 so by this logic 97 and 95 must be prime if square root passed but square root of 95 is 9.7467... (passed) so its "prime". But 95 clearly dividable by 5 fast algorithm in c#
int n=100000000;
bool [] falseprimes = new bool[n + 2];
int ed=n/6;
ed = ed * 6;
int md = (int)Math.Sqrt((double)ed);
for (int i = ed; i > md; i-=6)
{
falseprimes[i + 1] = true;
falseprimes[i - 1] = true;
}
md = md / 6;
md = md * 5;
for (int i = md; i > 5; i -= 6)
{
falseprimes[i + 1] = true;
falseprimes[i - 1] = true;
falseprimes[(i + 1)* (i + 1)] = false;
falseprimes[(i-1) * (i-1)] = false;
}
falseprimes[2] = true;
falseprimes[3] = true;
To generate prime numbers using 6 * k + - 1 rule use this algorithm:
int n = 100000000;
int j,jmax=n/6;
boolean[] primes5m6 = new boolean[jmax+1];
boolean[] primes1m6 = new boolean[jmax+1];
for (int i = 0; i <= jmax; i++){
primes5m6[i] = false;
primes1m6[i] = false;
}
for (int i = 1; i <= (int)((Math.sqrt(n)+1)/6)+1; i++){
if (!primes5m6[i]){
for (j = 6*i*i; j <= jmax; j+=6*i-1){
primes5m6[j]=true;
primes1m6[j-2*i]=true;
}
for (; j <= jmax+2*i; j+=6*i-1)
primes1m6[j-2*i]=true;
}
if (!primes1m6[i]){
for (j = 6*i*i; j <= jmax-2*i; j+=6*i+1){
primes5m6[j]=true;
primes1m6[j+2*i]=true;
}
for (; j <= jmax; j+=6*i+1)
primes5m6[j]=true;
}
}
System.out.print(2 + " ");
System.out.print(3 + " ");
for (int i = 1; i <= jmax; i++){
if (!primes5m6[i])
System.out.print((6*i-1) + " ");
if (!primes1m6[i])
System.out.print((6*i+1) + " ");
}

Add two array elements using loop

I am trying a task with arrays: add two elements and check if the sum is less than or equal to 50. If the condition is satisfied, it should break.
Example program:
public class HelloWorld {
public static void main(String []args)
{
int[] nums = new int[2];
for (int i = 0; i < 100; i++)
{
nums[i] = i + 1;
System.out.println(i);
}
System.out.println(nums[1]);
System.out.println(nums[2]);
if (nums[0]+nums[1]<=50)
{
System.out.printf("Sucessfully finished");
}
}
}
Of course, my program is not working. I want i value to store in the two elements
nums[0] = 1 and nums[1] = 2. I also want to add these two elements and check if the sum is less than or equal to 50. I have allocated two elements in the array which means nums want to add and check the current two elements of i and clear and adds next two elements and check if its less than or equal to 50.
nums[0]=1;
nums[1]=2; check <=50 . fails clear the the array elements and store next i value
nums[0]=3;
nums[1]=4; check <=50 . fails clear the the array elements and store next i value
...
nums[0]=25;
nums[1]=26; check <=50 .
There are a lot of ways to do this but here is a nifty trick that solves exactly this kind of problem.
int[] nums = new int[2];
for (int i = 0; i < 100; i++) {
nums[i % nums.length] = i + 1;
if (nums[0] + nums[1] <= 50) {
System.out.println("sum is less than or equal to 50");
break;
}
}
What the mod operator (%) does is calculate the remainder of i based on the array's length. This ensures that i goes from 0 to 99 but the array index always "resets" and stays within the range of the array. For example after i == 0 and i == 1, i will be incremented to out of bounds at i == 2 but 2 % 2 == 0. When i == 3, 3 % 2 == 1 and so on.
But as a side note, the condition you've described ("if the sum is less than or equal to 50...it should break") will be satisfied immediately (sums 1 at nums[0] and 0 at nums[1]) and the loop will not execute past the first iteration (i == 0). I'm not sure that's what you are wanting. Do you mean "not less than or equal to 50"?
int[] nums = new int[2];
for (int i = 0; i < 100; i++) {
nums[i % nums.length] = i + 1;
if (nums[0] + nums[1] > 50) {
System.out.println("sum was NOT less than or equal to 50");
break;
}
}
As an alternate solution finding this result can be very much shortened to the following while loop:
int i = 0;
// note sum of two consecutive integers will never be even (never 50)
while (i + ++i < 50);
System.out.println("min increments with sum > 50 was " + (i - 1) + " and " + i);
The output is min increments with sum > 50 was 25 and 26.
I believe, you need 1 more for loop, to go about checking each num[i] + num[i+1]. You can do it in a single for loop as well, but kept the code as simple as possible for your clarity.(As you are new to java programming ;))
public class HelloWorld{
public static void main(String[] args) {
int[] nums = new int[100];
for (int i = 0; i < 100; i++) {
nums[i] = i + 1;
System.out.println(i);
}
for (int i = 0; i < 99; i++) {
System.out.println(nums[i]);
System.out.println(nums[i+1]);
if (nums[i] + nums[i+1] == 50) {
System.out.printf("Successfully finished");
}
}
}
}
I'm not sure if this is what you meant. Have a try.
public static void main(String[] args) {
int[] nums = new int[100];
nums[0] =1;
for (int i = 1; i < 100; i++) {
nums[i] = i + 1;
if ((nums[i] +nums[i-1]) >= 50) {
System.out.printf("Successfully finished");
}
}
}
I'm not entirely sure on what your end goal is. If you just want to add two numbers (i, and i+1) and see if they are less than 50 then you can use this.
for (int i =0; i < 100; i++) {
int j = i+1;
int total = i+j;
if((i+(i+1)) < 50) {
System.out.println("Numbers '" + i + "' and '" + j + "' equal '" + total + "'.");
}
}
This will print out all the pairs of numbers that add to less than 50 along with what they add to.
I accept that you're probably wanting something more. :)

Categories