I have an array and i want to find number with most divisor. The problem is that i can find the number but i cant print how many divisor it is.
static void printDivisors(int n)
{
for (int i=1;i<=n;i++)
if (n%i==0)
System.out.print(i+" ");
}
public static void main(String args[])
{
System.out.println("The divisors of 100 are: ");
printDivisors(100);;
}
}
First of all, you only need to check values between 1 and n/2 to find the divisors of n. You won't find a divisor between n/2 and n (except for n itself). This will effectively reduce your execution time by half.
So your divisor finding method can be improved like below to count the number of divisors of a given number.
static int getNumDivisors(int n) {
int noOfDivisors = 0;
for (int i = 1; i <= n / 2; i++) {
if (n % i == 0) {
noOfDivisors++;
}
}
if (n > 1) {
noOfDivisors++; // n itself is a divisor of n
}
return noOfDivisors;
}
Then you need to iterate through the numbers array given by user and find the number of divisors for each number.
While iterating you need 2 variables
currentMaxDivisors - to store the max no of divisors you have found so far
numWithMaxDivisors - which number had the above number of divisors
If you happen to find a new number with more divisors, you update these variables with the new values. At the end, numWithMaxDivisors variable will contain the number with maximum divisors.
static int getNumDivisors(int n) {
int noOfDivisors = 0;
for (int i = 1; i <= n / 2; i++) {
if (n % i == 0) {
System.out.print(i + " ");
noOfDivisors++;
}
}
if (n > 1) {
noOfDivisors++; // n itself is a divisor of n
}
return noOfDivisors;
}
static int getNumWithMaxDivisors(int[] numbers) {
// Assuming numbers array has at least one element
int currentMaxDivisors = 0;
int numWithMaxDivisors = numbers[0];
for (int i = 0; i < numbers.length; i++) {
int numDivisors = getNumDivisors(numbers[i]);
if (numDivisors > currentMaxDivisors) {
numWithMaxDivisors = numbers[i];
}
}
return numWithMaxDivisors;
}
public static void main(String[] args) {
int[] numbers = new int[]{100, 55, 67, 2003, 12};
int numWithMaxDivisors = getNumWithMaxDivisors(numbers);
System.out.println(numWithMaxDivisors);
}
Related
Given a range of [1, 1000000000] we need to find prime numbers and all the digits of the prime number must be odd. (Example: 23 is not okay, 31 is okay)
If we go on by looping through each number and checking if it is prime etc, it is very slow. Is there a way to make this close to O(N) ?
I tried to eliminate as much as possible by looking at digits first. But after eliminating numbers with even digits the prime test is too slow.
for all numbers in [1, N]
check all digits, if any even digit, continue
check primality (this step is very slow)
And the primality test should not be very complex (probabilistic etc. is not possible, it must be possible to implement in a few minutes). The one I use is:
private static boolean isPrime(int n) {
boolean isPrime = true;
for (int divisor = 2; divisor <= n / 2; divisor++) {
if (n % divisor == 0) {
isPrime = false;
break;
}
}
return isPrime;
}
Maybe there is a trick to ensure a quick primality test but I couldn't find. Any suggestions? Thanks for reading.
You don't need to check all milliard numbers. Generate all numbers with only odd digits - there are at most 5^9~2 millions of them. Exclude those ending with 5 and not generate numbers divisible by 3 (in the moment of the last digit generation)
Then check these numbers for primality. Note that loop limit might be sqrt(n)
Ideone
class Ideone
{
static int oddcnt;
public static void checkprime(int x) {
for (int i=3; i <= Math.sqrt(x); i +=2)
if ((x % i) == 0)
return;
oddcnt++;
}
public static void genodd(int x, int curlen, int maxlen) {
x *= 10;
for (int i=1; i<10; i+=2) {
int nx = x + i;
checkprime(nx);
if (curlen < maxlen)
genodd(nx, curlen + 1, maxlen);
}
}
public static void main (String[] args) throws java.lang.Exception
{
genodd(0, 1, 8);
System.out.println(oddcnt);
}
}
The best way I can think of is to run a Prime Sieve of Eratosthenes to find all the primes in the range (0; sqrt(1000000000)) - which is around (0, 31622) - and time complexity O(n*log(log(n))) where n=31622. We will need those prime for a faster primality test.
Then, just loop through each number with odd digits - there are 5^10 = 9765625 ~ 10000000 such numbers. You saved 1000 times compared to iterating through all number in the original range.
The primality test using the primes we found in step 1 can be fast, as you only need to check with primes < sqrt(n), and you already have the primes. Even for the largest number in the range which is 999999999, the number of candidate primes is just 3432.
The following is a Java implementation
public class Execute {
private ArrayList<Long> primes = new ArrayList<>();
#org.junit.Test
public void findOddDecimalPrimes() {
primeSieve(32000);
System.out.println(primes.size());
for (int i = 0; i < 9765625; i++) {
String inBase5 = convertFromBaseToBase(i);
long evenDec = convertToOddDecimal(inBase5);
if (isPrime(evenDec)) {
System.out.println(evenDec);
}
}
}
private String convertFromBaseToBase(long i) {
return Long.toString(i, 5);
}
private long convertToOddDecimal(String str) {
StringBuilder s = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
s.append(1 + 2 * Integer.parseInt("" + str.charAt(i)));
}
return Long.parseLong(s.toString());
}
private boolean isPrime(long n) {
for (int i = 0; i < primes.size(); i++) {
if (primes.get(i) * primes.get(i) > n) break;
long divisor = n / primes.get(i);
if (divisor * primes.get(i) == n) return false;
}
return true;
}
/**
* References: www.geeksforgeeks.org
*/
private void primeSieve(int n)
{
// Create a boolean array "prime[0..n]" and initialize
// all entries it as true. A value in prime[i] will
// finally be false if i is Not a prime, else true.
boolean prime[] = new boolean[n+1];
for(int i=0;i<n;i++)
prime[i] = true;
for(int p = 2; p*p <=n; p++)
{
// If prime[p] is not changed, then it is a prime
if(prime[p] == true)
{
// Update all multiples of p
for(int i = p*p; i <= n; i += p)
prime[i] = false;
}
}
for (int i = 2; i < prime.length; i++) {
if (prime[i]) this.primes.add(Long.valueOf(i));
}
}
}
If your numbers are in order, you can optimize your isPrime function.
Here is a js sample version.
var primes = [];
function checkDigits(n) {
while(n > 1) {
var d = n % 10;
if ( d % 2 == 0) { return false; }
n = parseInt(n/10,10);
}
return true;
}
function isPrime(n) {
for(var i = 1; i < primes.length; i++) {
if(n % primes[i] == 0) {
return false;
}
}
var lastPrime = primes.length > 2 ? primes[primes.length - 1] : 1;
var inc = 2;
for(var i = lastPrime + inc; i < Math.sqrt(n); i += inc) {
if(n % i == 0) {
return false;
}
}
primes.push(n);
return true;
}
for(var i = 1; i < 100; i++) {
if(checkDigits(i) && isPrime(i)) {
console.log(i);
}
}
This is an open question in math and computer science in general.
In a nutshell no, there is no know way to solve that problem in O(1) to get your loop running in O(N) over the whole range.
If you solve that, dont tell anyone, and go get rich by breaking most of the encryptions today that use large prime numbers.
What you could do though, is make the loop over the devisor a bit smaller by useing sqrt(n).
That will bring that inner loop down from O(N^2) to O(sqrt(N))
And the whole complexity from O(N^2) to O(N*sqrt(N))=O(N^(3/2))
Anotger optimization would be to check the odd digits first beforre doing the complex Prime calculation
I have a program that is supposed to decrypt a number to its primes. The primes also have an order: for instance, 2 is the 1st prime number, 3 is the second 5 is the third and so on. The indexes are 1 is for a, two is for b, three is for c and so on. I don't know how to compare the two array lists in order to assign an index to each prime so I can decode a word which is encrypted in the number 72216017. The number 72216017 has the primes 17,19,47,67,71. If 2,3,5,7,11... are a,b,c,d,e... these five prime numbers make up the word ghost, I just don't know how to assign and sort these numbers by their index.
package name;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class PrimeFactorsEffective {
private static int z;
private int w = z;
public static List<Integer> primeFactors(int numbers) {
int n = numbers;
List<Integer> factors = new ArrayList<Integer>();
for (int i = 2; i <= n / i; i++) {
while (n % i == 0) {
factors.add(i);
n /= i;
}
if (n > 1) {
factors.add(n);
System.out.println(factors);
z = Collections.max(factors);
}
}
return factors;
}
public static void main(String[] args) {
System.out.println("Primefactors of 72216017");
for (Integer integer : primeFactors(72216017)) {
System.out.println(integer);
}
List<Integer> factors1 = new ArrayList<Integer>();
List<String> index1 = new ArrayList<String>();
int i;
int element = 0;
int num = 0;
int maxCheck = z; // maxCheck limit till which you want to find prime numbers
boolean isPrime = true;
String primeNumbersFound = "";
//Start loop 1 to maxCheck
for (i = 1; i <= maxCheck; i++) {
isPrime = CheckPrime(i);
if (isPrime) {
primeNumbersFound = primeNumbersFound + i + " ";
factors1.add(i);
factors1.get(num);
}
}
System.out.println("Prime numbers from 1 to " + maxCheck + " are:");
System.out.println(factors1);
}
public static boolean CheckPrime(int numberToCheck) {
int remainder;
for (int i = 2; i <= numberToCheck / 2; i++) {
remainder = numberToCheck % i;
if (remainder == 0) {
return false;
}
}
return true;
}
}
You can store the primes in a List (primes in this list will be in increasing order). Now you can use Collections.BinarySearch to get the index of the prime for which you wan to find the corresponding alphabet. Once you got the index (index here according to you starts from 1, so a's index is 1, b's index is 2, c's index is 3 and so on) you can do simply something like char currentCharacter = (char) ('a' + primeIndex - 1) and the variable currentCharacter will store the alphabet corresponding to primeIndex.
Some other minor things that I'd like to suggest:
Which checking whether a number is prime or not, you can simply check upto square-root of numberToCheck. So you can replace your loop for (int i = 2; i <= numberToCheck / 2; i++) to for (int i = 2; i*i <= numberToCheck; i++). Note that It is not a good idea to calculate square-root using Math.sqrt, instead you can have a condition like i*i <= numberToCheck.
Please refrain from naming your packages that seem to be random.
As of Java SE 7 explicit type-arguments while initializing the list are not required. You can replace List<Integer> factors1 = new ArrayList<Integer>() with List<Integer> factors1 = new ArrayList<>(). Please read this for more information.
Your factor method don't really look good to me, it don't give correct results. Please see the following method that gives correct result:
{{
public static List<Integer> primeFactors(int numbers) {
int n = numbers;
List<Integer> factors = new ArrayList<>();
for (int i = 2; n>1; i++) {
while (n % i == 0) {
factors.add(i);
n /= i;
}
}
z = Collections.max(factors);
return factors;
}
I need to count all the divisors for every number in the range 1 to n. I have written down below an implementation for, given an integer num, it counts the number of divisors of num. Its complexity is O(sqrt(n)). So over all complexity comes out to be O(n * sqrt(n)). Can it be reduced? If YES, then can you give an algorithm for that?
CODE :
public static int countDivisors(int num)
{
int limit = (int)Math.sqrt(num);
int count = 2;
for(int i = 2 ; i <= limit ; i++)
{
if(num % i == 0)
{
count++;
if(num / i != i)
{
count++;
}
}
}
return count;
}
PS:
This function will be called n times.
You can improve upon the naive approach using kind of a generalized Sieve of Eratosthenes. Instead of just marking the number as composite also store its first divisor that you found (I do this in the function computeDivs below).
class Main
{
// using Sieve of Eratosthenes to factorize all numbers
public static int[] computeDivs(int size) {
int[] divs = new int[size + 1];
for (int i = 0; i < size + 1; ++i) {
divs[i] = 1;
}
int o = (int)Math.sqrt((double)size);
for (int i = 2; i <= size; i += 2) {
divs[i] = 2;
}
for (int i = 3; i <= size; i += 2) {
if (divs[i] != 1) {
continue;
}
divs[i] = i;
if (i <= o) {
for (int j = i * i; j < size; j += 2 * i) {
divs[j] = i;
}
}
}
return divs;
}
// Counting the divisors using the standard fomula
public static int countDivisors(int x, int[] divs) {
int result = 1;
int currentDivisor = divs[x];
int currentCount = 1;
while (currentDivisor != 1) {
x /= currentDivisor;
int newDivisor = divs[x];
if (newDivisor != currentDivisor) {
result *= currentCount + 1;
currentDivisor = newDivisor;
currentCount = 1;
} else {
currentCount++;
}
}
if (x != 1) {
result *= currentCount + 1;
}
return result;
}
public static int countAllDivisors(int upTo) {
int[] divs = computeDivs(upTo + 1);
int result = 0;
for (int i = 1; i <= upTo; ++i) {
result += countDivisors(i, divs);
}
return result;
}
public static void main (String[] args) throws java.lang.Exception {
System.out.println(countAllDivisors(15));
}
}
You can also see the code executed on ideone here.
In short I use the sieve to compute the biggest prime factor for each number. Using this I can compute the factor decomposition of every number very efficiently (and I use this in countDivisors).
It is hard to compute the complexity of the sieve but a standard estimate is O(n * log(n)). Also I am pretty confident it is not possible to improve on that complexity.
You can do much better than O(n.sqrt(n)) by using simple iteration. The code is in C++, but you can easily get the idea.
#include <iostream>
#include <vector>
using namespace std;
void CountDivisors(int n) {
vector<int> cnts(n + 1, 1);
for (int i = 2; i <= n; ++i) {
for (int j = i; j <= n; j += i) {
cnts[j]++;
}
}
for (int i = 1; i <= n; ++i) {
cout << cnts[i] << " \n"[i == n];
}
}
int main() {
CountDivisors(100);
return 0;
}
Running time is n/1 + n/2 + n/3 + n/4 + ... + n/n which can be approximated by O(nH(n)), where H(n) is the harmonic series. I think the value is not bigger than O(nlog(n)).
Using iteration is OK for relatively small numbers. As soon as the number of divisors is getting bigger (over 100-200), the iteration is going to take a significant amount of time.
A better approach would be to count the number of divisors with help of prime factorization of the number.
So, express the number with prime factorization like this:
public static List<Integer> primeFactorizationOfTheNumber(long number) {
List<Integer> primes = new ArrayList<>();
var remainder = number;
var prime = 2;
while (remainder != 1) {
if (remainder % prime == 0) {
primes.add(prime);
remainder = remainder / prime;
} else {
prime++;
}
}
return primes;
}
Next, given the prime factorization, express it in the exponent form, get exponents and add 1 to each of them. Next, multiply resulting numbers. The result will be the count of divisors of a number. More on this here.
private long numberOfDivisorsForNumber(long number) {
var exponentsOfPrimeFactorization = primeFactorizationOfTheNumber(number)
.stream()
.collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()))
.values();
return exponentsOfPrimeFactorization.stream().map(n -> n + 1).reduce(1L, Math::multiplyExact);
}
This algorithm works very fast. For me, it finds a number with 500 divisors within less than a second.
I've been noticing a theme with some of the Project Euler problems. They require a huge amount of time to complete. (Problems like Largest Palindrome and 10,001st Prime) I was hoping there could be some way to optimize the code to make it better. I let this one run for over 24 minutes and it didn't finish.
public class Seven
{
public static void main(String[] args)
{
//Declare Variables
int primeCount = 0;
int numCount = 1;
int latestPrime = 0;
while(primeCount <= 10001)
{
if(isPrime(numCount))
{
primeCount++;
latestPrime = numCount;
}
numCount++;
}
System.out.println("The 10,001st prime is: " + latestPrime);
}
//This method will determine if a number is prime
public static boolean isPrime(long num)
{
//Check for even number
if(num % 2 == 0)
return false;
//Check for non-prime odd numbers
for(long i = 3; i <= num; i += 2)
{
if(num % i == 0)
return false;
}
//Return that the number is prime
return true;
}
}
You're doing a lot of repetitions, you don't need to loop through entire number in the for loop, just go until square root.
This runs in a second.
// Check for non-prime odd numbers
for (long i = 3; i <= Math.sqrt(num) +1; i += 2) {
if (num % i == 0)
return false;
}
If you want to optimize even more, you could store prime numbers in an array and only check if the number divisible by the previous prime numbers.
This program prints 10001 first prime numbers. As #Tejash Desai suggested, 2 optimizations could be done:
(1) keep the found prime numbers in a list so that tests of new primes needs to be done only on items inside this list, rather than all odd numbers; and
(2) test againts factors only up to square root of a number.
void printPrimes() {
// Find first 10001 primes
int p = 0;
for (var i = 2; i <= 10001; i++) {
p = nextPrime();
Console.WriteLine("Prime #{0}: {1}", i, p);
}
}
// Set of known primes
List<int> primes = new List<int>() {2};
// Find the prime next to the last one that was found
int nextPrime() {
int k = primes[primes.Count - 1] + 1;
while (!testPrimeUsingKnownSetOfPrimes(k)) {
k = k + 1;
}
primes.Add(k);
return k;
}
// Check if a number is prime, using the set of known primes
bool testPrimeUsingKnownSetOfPrimes(int n) {
foreach (var p in primes) {
// Largest prime factor of a number can't be greater than square root of the number
if (p > Math.Sqrt(n)) {
return true;
}
if (n % p == 0) {
return false;
}
}
return true;
}
PS Written in C#.
Loop only till less than or equal to the square root of n
//Check for non-prime odd numbers for(long i = 3; i <= Math.sqrt(num); i += 2) { if(num % i == 0) return false; }
Also, another optimization would be to keep storing all the primes you've come across till now in an ArrayList and then only traverse the loop in that list.
//Check for non-prime odd numbers for(int i = 0; i <= arrayList.size(); i ++) { if(num % arrayList.get(i) == 0) return false; } arrayList.add(num);
I am attempting Problem 50 of project Euler.
The prime 41, can be written as the sum of six consecutive primes:
41 = 2 + 3 + 5 + 7 + 11 + 13 This is the longest sum of consecutive
primes that adds to a prime below one-hundred. The longest sum of
consecutive primes below one-thousand that adds to a prime, contains
21 terms, and is equal to 953. Which prime, below one-million, can be
written as the sum of the most consecutive primes?
Here is my code:
public class consPrime
{
static int checker(int ar[],int num,int index) //returns no.of consecutive
{ //primes for the given num
while(true)
{
int temp=num;
for(int i=index;i>=0;i--)
{
temp=temp-ar[i];
if(temp==0)
{
return (index-i+1);
}
}
index--;
if(index==0)
return 0;
}
}
public static void main(String args[])
{
int n=100000;
int ar[]=new int[n];
int total=0;int flag;
for(int i=2;i<1000000;i++) //Generates an array of primes below 1 million
{
flag=1;
for(int j=2;j<=Math.sqrt(i);j++)
{
if(i%j==0)
{
flag=0;
break;
}
}
if(flag==1)
{
ar[total]=i;
total++;
}
}
int m=0;
int Big=0;
for(int i=total;i>=0;i--) //Prints the current answer with no.of prime
{
m=checker(ar,ar[i],i-1);
if(Big<=m)
{Big=m;
System.out.println(ar[i]+" "+Big);
}
}
}
}
Basically it just creates a vector of all primes up to 1000000 and then loops through them finding the right answer. The answer is 997651 and the count is supposed to be 543 but my program outputs 990707 and 75175 respectively. What might be wrong?
Several big problems:
Some minor problem first: learn to proper indent your code, learn to use proper naming convention. In Java, variable names uses camelCasing while type name uses PascalCasing.
Lots of problems in your logics: you loop thru the prime number array, until you hit zero or until looped thru all numbers in the array. However, please be awared that, there is underflow/overflow for integer. It is possible that the "temp" keeps on deducts and become negative and become positive and so-on-and-so-forth and hit zero. However that's not the correct answer
You only tried to find the consecutive numbers that ends at index - 1. For example, to check for prime number at index 10, you are finding consecutive primes from index 9 backwards. However consecutive prime sum up to your target number rarely (in fact almost never, except for 5) contains the "previous" prime number. The whole logic is simply wrong.
Not to mention the incorrect parameters you passed for checker, which is mentioned by comment of user #pm-77-1
Here is another approach that takes 43 ms.
It is based on the following approach:
1) The primes <= 1000000 are generated using a sieve
2) It iterates in O(n2) through all numbers and it counts the consecutive primes. The first loop changes the first element of the sequence, the second one takes the elements starting from that position and adds them to a sum. If the sum is prime and it consists of the biggest number of primes, than it is kept in a variable.
import java.util.ArrayList;
import java.util.List;
public class P50 {
private final static int N = 1_000_000;
public static void main(String[] args) {
boolean primes[] = generatePrimes(N);
List<Integer> primeIntegers = new ArrayList<Integer>();
for (int i = 0; i < primes.length; i++) {
if (primes[i]) {
primeIntegers.add(i);
}
}
int count = 0;
int sum = 0;
int finalSum = 0;
int finalCount = 0;
int totalPrimes = primeIntegers.size();
for (int start = 0; start < totalPrimes; start++) {
sum = 0;
count = 0;
for (int current = start; current < totalPrimes; current++) {
int actual = primeIntegers.get(current);
sum += actual;
if ( sum >= N ) {
break;
}
if ( primes[sum] ) {
if ( count > finalCount ) {
finalCount = count;
finalSum = sum;
}
}
count++;
}
}
System.out.println(finalSum);
}
private static boolean[] generatePrimes(int n) {
boolean primes[] = new boolean[n];
for (int i = 0; i < n; i++) {
primes[i] = true;
}
primes[0] = false;
primes[1] = false;
// i = step
for (int i = 2; i * i < n; i++) {
if (primes[i]) {
for (int j = i * i; j < n; j += i) {
primes[j] = false;
}
}
}
return primes;
}
}