Sieve of Eratosthenes (min and max) - java

I am using the Sieve of Eratosthenes algorithm to find the prime numbers in a range (from a min value to a max value). However, I cannot seem to get it to work if I include a min value.
Here is my code in Java:
protected static List<Integer> getSievePrimes(int a, int b) {
List<Integer> primeNumbers = new ArrayList();
boolean [] isComposite = new boolean [b + 1];
isComposite[1] = true;
// Mark all composite numbers
for (int i = 2; i <= b; i++) {
// for (int i = a == 1 ? 2 : a; i <= b; i++) {
if (!isComposite[i]) {
// 'i' is a prime number
//if (i >= a) {
primeNumbers.add(i);
//}
int multiple = 2;
while (i * multiple <= b) {
isComposite [i * multiple] = true;
multiple++;
}
}
}
return primeNumbers;
}
As you can see it currently only caters for the max value (b), and not the min value (a).
Question
How can I modify the method above to cater for both min and max?

public boolean isPrime( int test )
{
int k;
if( test < 2 )
return false;
else if( test == 2 )
return true;
else if( ( test > 2 ) && ( test % 2 == 0 ) )
return false;
else
{
for( k = 3; k < ( test/2 ); k += 2 )
{
if( test % k == 0 )
return false;
}
}
return true;
}
public void sieveOfEratosthenes( int first, int last )
{
boolean[ ] sieve = new boolean[ ( last - first ) + 1 ];
int count = 0;
int index = 0;
int cursor = first;
int end = last;
while( cursor <= end )
{
if( isPrime( cursor ) != sieve[ index ] )
{
System.out.println( cursor+" " );
count++;
}
cursor++;
index++;
}
cursor = first;
if( count == 0 )
System.out.println( "There are "+count+" primes from "+cursor+" to "+end+"." );
else if( count == 1 )
System.out.println( "is the "+count+" prime from "+cursor+" to "+end+"." );
else
System.out.println( "are the "+count+" primes from "+cursor+" to "+end+"." );
}

Related

Advice on speeding up prime number counter

How can I improve the logic of the following code? The purpose is to compute the number of primes from 1 to the user input (limitNo). The program works fine except it takes a while, more than the usual 1-3 secs, to generate a result for huge numbers like 99999.
public static int countPrime(int limitNo) {
int noOfTimes = 0, noOfRounds = 0; int o = 1;
while (o <= limitNo) {
for (int i = 1; i <= o; i++) {
if (o%i == 0) {
noOfRounds++;
}
}
if (noOfRounds == 2) {
noOfTimes++;
}
noOfRounds = 0;
o++;
}
return noOfTimes;
}
The code can be improved by
Separating some of the lines to make an isPrime() method.
Changing limits of the for loop so that if the condition is met that means the number is not prime.
public static boolean isPrime(int num) {
for ( int i = 2 ; i < num ; i++ ) {
if ( num % i == 0 ) {
return false;
}
}
return true;
}
Replacing the code in the method with isPrime() and change the start int o = 2 ;.
public static int countPrime(int limitNo) {
int noOfTimes = 0;
int o = 2;
while ( o <= limitNo ) {
if ( isPrime(o) ) {
noOfTimes++;
}
o++;
}
return noOfTimes;
}
Of course, there are better and more improvements like:
for ( int i = 2 ; i <= num/2 ; i++ )
for ( int i = 2 ; i <= Math.sqrt(num) ; i++ )

Each substring of a certian length of a binary substring should have at least one '1' character

You have been given a binary string containing only the characters '1' and '0'.
Calculate how many characters of the string need to be changed in order to make the binary string such that each of its substrings of at least a certain length contains at least one "1" character.
I came to think of the following idea but it fails for many testcases:
public static int minimumMoves(String s, int d) {
int n = s.length();
int i=0, answer = 0;
while(i<n)
{
boolean hasOne = false;
int j=i;
while(j<n && j<i+d)
{
if(s.charAt(j) == '1')
{
hasOne = true;
break;
}
j++;
}
if(!hasOne) {
answer++;
i += d;
}
else i++;
}
return answer;
}
Also my algorithm runs on O(|s|2) time. Can anyone suggest ideas on O(|s|) time?
Just throwing off an idea:
return s.split("(?<=\\G.{" + String.valueof(d) + "})").stream().filter(str -> str.contains("1")).count()
You just need to break ensure there is no run of d zeros.
public static int minimumMoves(String s, int d) {
int result = 0;
int runLength = 0;
for(char c: s.toCharArray()) {
if (c == '0') {
runLength += 1;
if (runLength == d) { // we need to break this run
result += 1;
runLength = 0;
}
} else {
runLength = 0;
}
}
return result;
}
I used the sliding window technique and Deque to solve this. This is my accepted solution:
public static int minimumMoves(String s, int d) {
int n = s.length();
Deque<Character> dq = new LinkedList<>();
int count = 0, answer = 0;
for(int i=0; i<d; i++)
{
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
}
if(count == 0) {
answer++;
count++;
dq.removeLast();
dq.addLast('1');
}
int i=d;
while(i<n)
{
if(dq.getFirst() == '1') count--;
dq.removeFirst();
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
if(count == 0)
{
answer++;
dq.removeLast();
dq.addLast('1');
count++;
}
i++;
}
return answer;
}
You just need to use a sliding window and a count of 1s so far at each index. Use a sliding window of d and if you don't see any ones so far, update the last index of that window with 1 and increment the result.
Code below:
public static int minimumMoves(String s, int d) {
int n = s.length();
int[] count = new int[n+1];
int res = 0;
for ( int i = 1; i <= d; i++ ) {
if ( s.charAt(i-1) == '1') count[i] = count[i-1]+1;
else count[i] = count[i-1];
}
if ( count[d] == 0 ) {
res++;
count[d] = 1;
}
for ( int i = d+1; i <= n; i++ ) {
if ( s.charAt(i-1) == '0' ) {
count[i] = count[i-1];
int ones = count[i] - count[i-d];
if ( ones == 0 ) {
count[i] = count[i-1] + 1;
res++;
}
} else {
count[i] = count[i-1] + 1;
}
}
return res;
}
Thought of another implementation you can do for this by working from the maximum possible changes (assumes at start that all values are '0' in String), reduce it when it finds a '1' value, and then jump to the next substring start. This allows it to run in O(n) and Ω(n/m) (n = String length, m = Substring length).
public static int minimumMoves(String s, int d)
{
char[] a = s.toCharArray();
//Total possible changes (not counting tail)
if(a.length < d)
return 0;
int t = (int) a.length / d;
//Total possible changes (counting tail)
//int t = (int) Math.ceil((double) a.length / (double) d);
for(int i = 0; i < a.length; i++)
{
if(a[i] == '1')
{
t--;
//Calculate index for start of next substring
i = (i / d + 1) * d - 1;
}
}
return t;
}

Zigzag conversion

Question is : The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H N
A P L S I I G
Y I R
And then read line by line: "PAHNAPLSIIGYIR"
I have written below code, appearantly it works fine, but I might miss some corner cases. Could you help me to find all the corner cases for this question on my answer?
public static String zigZagConversion(String s , int rowNum){
if (s == null){
throw new IllegalArgumentException();
}
if (rowNum == 1){
return s;
}
StringBuilder str = new StringBuilder();
int step = 2 * rowNum - 2 ;
for (int i = 0 ; i < rowNum ; i++){
if( i == 0 || i == rowNum -1){
for (int j = i ; j < s.length() ; j +=step){
str.append(s.charAt(j));
}
}
else{
int step2 = 2* (rowNum - i - 1);
int step3 = step - step2;
int k = i;
boolean flag = true;
while (k < s.length()){
str.append(s.charAt(k));
if(flag){
k += step2;
flag = false;
}
else{
k +=step3;
flag = false;
}
}
}
}
return str.toString();
}
It gives incorrect output for "PAYPALISHIRING", 4
P I N
A L S I G
Y A H R
P I
So the correct answer should be PINALSIGYAHRPI.
But your program gives PINALIGYAIHRNPI:
an "S" is missing, one extra "I" and one extra "N".
Your revised version is still incorrect, it gives PINALSIIGYAHNPI.
The problem is in the while loop in the middle.
You need to alternate the step counting,
setting the flag on and off.
Your mistake was to only set it off once, and never back on again.
str.append(s.charAt(k));
if (flag) {
k += step2;
flag = false;
} else {
k += step3;
flag = true;
}
With this correction, I believe your solution is correct. (I also added a minor improvement there, extracting the common str.append(s.charAt(k)); from the if-else branches.
My solution on leetcode forum:
https://leetcode.com/problems/zigzag-conversion/discuss/549451/Java-Solution-O(n)-with-algorithm
The mathematic algorithm for zigzag is:
originalDiff = numRows * 2 - 2;
If -> 'currRow' equals First or last lines
use the originalDiff (numRows * 2 - 2)
Else ->
For each new line:
upperDiff += 2,
lowerDiff -=2
Examples:
numRows =2 -> originalDiff = 2
PYAIHRN
APLSIIG
3 -> 4
P A H N
A P L S I I G
Y I R
numRows = 4 -> originalDiff = 6
P I N
A L S I G
Y A H R
P I
numRows = 5 -> originalDiff = 8
P H
A SI
Y I R
P L I G
A N
*/
My solution:
class Solution {
public String convert(String s, int numRows) {
if(numRows == 1) {
return s;
}
String newString = "";
int originalDiff = numRows * 2 - 2;
int diff = originalDiff;
int upperDiff = 0;
boolean isGoingDown = true;
int currIndex = 0;
int currRow = 0;
int startingIndex = 0;
for(int i = 0; i < s.length(); i++) {
System.out.println(currIndex);
newString += s.charAt(currIndex);
if(currRow == 0 || currRow == numRows - 1) {
currIndex += originalDiff;
} else {
if(isGoingDown) {
currIndex += diff;
isGoingDown = !isGoingDown;
} else {
currIndex += upperDiff;
isGoingDown = !isGoingDown;
}
}
if(currIndex >= s.length()) {
currRow++;
diff -= 2;
upperDiff += 2;
currIndex = currRow;
isGoingDown = true;
}
if(currRow == numRows) {
i = s.length();
}
}
return newString;
}
}
Zigzag conversion from leetcode in Javascript
Solution
const zigzag = (str, num) => {
if (num === 1) {
return str;
}
let check = true;
let result = [];
let i = 0;
while (i < str.length) {
result.push([]);
let j = 0;
while (j < num) {
if (check){
result[result.length-1].push(str[i]);
i++;
} else {
if (j == 0) {
result[result.length-1].push(null);
} else if (j === num-1) {
result[result.length-1].unshift(null);
} else {
result[result.length-1].unshift(str[i]);
i++;
}
}
j++;
}
check = !check;
}
let zigzag = [];
for (let k = 0; k < num; k++){
for(let l = 0; l < result.length; l++) {
zigzag.push(result[l][k]);
}
}
return zigzag.join("");
}
Example Input
zigzag("ABCD", 3)
Output
ABDC
Run
https://repl.it/#VinitKhandelwal/zigzag-conversion-javascript
Using HashMap
public String convert(String s, int numRows) {
if (numRows == 1){
return s;
}
StringBuilder result = new StringBuilder();
Map<Integer, StringBuilder> map = new HashMap<>();
for (int i = 0; i < numRows; i++) {
map.put(i,new StringBuilder());
}
int it = 0;
boolean flip = true;
for (int i = 0; i < s.length(); i++) {
if (flip) {
if(it<s.length()){
map.get(it).append(s.charAt(i));
it++;
}
} else {
map.get(it).append(s.charAt(i));
it--;
}
if (it + 1 == numRows || it == 0)
flip = !flip;
}
for (Map.Entry entry: map.entrySet()) {
result.append(entry.getValue());
}
return result.toString();
}
My Solution is traversing the string in the same way it is said in the problem, it is better to make string array of size numrows and the rest is storing the string character as it is in the logic,
you can keep the index and when that index is 0 i.e at the starting then we have to go till the end of the row and then except for first and last row, every array will have diagonal element.
So after traversing till the end then assign index = numrows - 2 and save in the respective array string and decrease and do the same till index >0 and then again traverse till the end row, do this and when we reach the end of the string then break from the loop.
and then concate all the string of string array in a new res string.
class Solution {
public String convert(String s, int n) {
if(n==1 || n>=s.length())
return s;
String[] a = new String[n]; //string array
int ind=0; // index for the string array
boolean flag=true;
int cnt=0; //to keep the counter till where we have traversed the string
while(true && flag)
{
if(ind==0)
{
for(int i=0;i<n;i++)
{
a[i] += s.charAt(cnt);
cnt++;
if(cnt==s.length())
{
flag=false;
break;
}
} // here it has reached the end so we assign here
ind = n-2;
}
else if(ind>0 && ind<n && flag)
{
a[ind] += s.charAt(cnt);
cnt++;
if(cnt==s.length())
{
flag=false;
break;
}
ind--; // to move diagonally up
}
}
String res = new String("");
for(int i=0;i<a.length;i++)
{
// System.out.println(a[i].substring(4));
res += a[i].substring(4);
}
return res;
}
}
Following is the simple solution.
class Solution:
def convert(self, s: str, numRows: int) -> str:
if numRows <= 1:
return s
res = ""
p = numRows * 2 - 2
temp = p
for i in range(0,numRows):
index = i
flag = 0
while index < len(s):
res = res + s[index]
if i == 0 or i == numRows-1:
index = index + p
else:
if flag == 0:
index = index + temp
flag = 1
else:
index = index + p-temp
flag = 0
temp = temp - 2
return res
zigzag-conversion Complete JavaScript-based solution
Created an Array of an array of row lengths. The main motive is to arrange characters in 2D array form and concat string row-wise.
var convert = function(s, numRows) {
let array =[],c=0,str='';
for(let row =0; row<numRows ; row++) {
array[row] = new Array();
}
while(c < s.length) {
for(let row =0; row<numRows ; row++) {
if((row+1)%numRows ==0) {
array[row].push(s[c]);
c++;
break;
} else {
array[row].push(s[c]);
c++;
}
}
for(let rr = numRows-2 ; rr>0;rr--) {
array[rr].push(s[c]);
c++;
}
}
for(let row =0; row<numRows ; row++) {
for(let i=0;i<array[row].length;i++){
if(array[row][i]){
str+=array[row][i]
}
}
}
return str
};
convert("PAYPALISHIRING",3)

program is not reading the for loop

import java.lang.Math;
import java.text.*;
public class Problem4 {
public static int reverse( int n ) {
int i = 0;
while ( n != 0 ) {
int r = n % 10;
i = (i * 10) + r;
n /= 10;
}
return i;
}
public static boolean isPalindrome( int n ) {
return ( n == reverse(n) ) ? true : false;
}
public static void main( String[] args ) {
int jHi=0, jlow=0, dec=0;
int P=1;
int i=999, j=1;
for ( i=999; i <= 100; i = i - 1 )
{
if ( i % 11 == 0 )
{
jHi = 999;
jlow = 100;
dec = 1;
}
else
{
jHi = 990;
jlow = 100;
dec = 11;
}
for ( j = jHi; j >= jlow; j = j - dec )
{
P = i * j;
if ( isPalindrome(P) )
{
break;
}
else
{
continue;
}
}
}
System.out.println( "Largest Palindrome is " + P );
}
}
Your for loop does not execute because the loop condition i<=100 is never met with an initial value of i=999.
Since you want your loop to count downwards, change
for(i=999; i<=100; i=i-1)
to
for(i=999; i>=100; i=i-1)
i=999; i<=100; i=i-1 --change it as i=999; i>=100; i=i-1
This means "start with i as 999 and do it while i is less or equal than 100 decreasing i by one in each step":
for(i=999; i<=100; i=i-1)
Your for loop will not execute for very first time and hence no operation. Always use proper condition.

Testing if a number inside an Array is a duplicate and then removing it

So my Problem is i have to list the prime factors of a number inside an Array and the power of that prime factor in another one on the same positions inside their given array(so if you want the primefactors of 60 i would need to return an array with contents like this: primes: {2, 3, 5} powers {2, 1, 1} => (2*2)*(3*1)*(5*1) = 60.
I now have the following code to determine the duplicates inside the primes Array but how can i now instead of printing them to the console save them in another variable to then use them for the powers Array?
long current = primes[0];
boolean found = false;
for( int i = 0; i < primes.length; i++) {
if( current == primes[i] && !found) {
found = true;
}
else if( current != primes[i] ) {
System.out.print(" " + current);
current = primes[i];
found = false;
}
The full code would then be:
public class Algebra {
public static long [][] primfaktorzerlegung(long n){
int position = 0;
long[] primes = new long [0];
long [] powers = new long [0];
while(n%2 == 0) {
primes[position] = 2;
position++;
n = n / 2;
}
for (int i = 3; i <= Math.sqrt(n); i+= 2)
{
while (n%i == 0)
{
n /= i;
}
}
long current = primes[0];
boolean found = false;
for (int i = 0; i < primes.length; i++) {
if (current == primes[i] && !found) {
found = true;
} else if (current != primes[i]) {
current = primes[i];
found = false;
}
}
long[][] z = {primes,powers};
return z;
}
}
It's obviously unfinished but to show the whole thing i post it anyways.
You want the frequency of each prime, and there’s a standard way to do this in java. Also, since you don’t know how many primes there will be you’re better to use a List.
But you don’t even need to use either of those, just use a Map<Long, Long> and accumulate both primes and powers in one pass:
Map<Long, Long> primePowers = new LinkedHashMap<>();
for (int i = 2; i <= Math.sqrt(n); i+= 2) {
while (n%i == 0) {
primePowers.put(i, primePowers.getOrDefault(i, 0L) + 1);
n /= i;
}
}
// convert the Map to the return value
long[] primes, powers = new long[primePowers.size()];
int i = 0;
for (Map.Entry<Long, Long> entry : primePowers.entrySet()) {
primes[i] = entry.getKey();
powers[i] = entry.getValue();
}
return new long[][]{primes,powers};
FYI a LinkedHashMap iterates over its entries in insert order.
As a design point, the return type long[][] is not a good choice. Any situation where 2 arrays must agree on their elements aligning is poor design.
Code:
import java.util.ArrayList;
import java.util.List;
public class Primes {
static long getPowerOf( long power, long n, List<Long> primes, List<Long> powers ) {
if(( n % power ) == 0 ) {
long count = 0L;
while(( n % power ) == 0 ) {
++count;
n = n / power;
}
primes.add( power );
powers.add( count );
}
return n;
}
static long[][] getPrimes( long n ) throws Exception {
final List<Long> primes = new ArrayList<>();
final List<Long> powers = new ArrayList<>();
n = getPowerOf( 2, n, primes, powers );
for( long i = 3; n > 1; i += 2 ) {
n = getPowerOf( i, n, primes, powers );
}
if( n > 1 ) {
throw new Exception( "More primes needed" );
}
final long[][] result = new long[2][];
result[0] = new long[primes.size()];
result[1] = new long[powers.size()];
for( int i = 0; i < primes.size(); ++i ) {
result[0][i] = primes.get( i );
}
for( int i = 0; i < powers.size(); ++i ) {
result[1][i] = powers.get( i );
}
return result;
}
static void showPrimes( long[] primes, long[] powers ) {
boolean tail = false;
for( int i = 0; i < primes.length; ++i ) {
if( powers[i] > 0 ) {
if( tail ) {
System.out.print( " + " );
}
else {
tail = true;
}
System.out.print( primes[i] + "x" + powers[i]);
}
}
System.out.println();
}
public static void main( String[] args ) throws Exception {
final long[][] result = getPrimes( 2*2*3*5*5*7*23*23*23 );
showPrimes( result[0], result[1] );
}
}
Output:
2x2 + 3x1 + 5x2 + 7x1 + 23x3
Notes:
Using a class in place of long[][] for primes and powers will be better, like this:
class PrimeUsage {
long prime;
long power;
}
PrimeUsage[] or List<PrimeUsage> or Set<PrimeUsage>

Categories