This is my solution to the first question in Project Euler.
Could someone please help reduce the time complexity of this working code?
Problem:
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
public class Sum {
private static final int n = 1000;
public static void main(String[] args) {
for (int i = 1, sum = 0; i <= n; i++) {
if ((i % 3 == 0) || (i % 5 == 0)) {
System.out.println(sum += i);
}
}
}
}
I am using the formula provided by phatfingers.
You can have numbers that are divisible by 15 (3 * 5), so you kinda have to subtract that amount.
Because the formula without k works for all natural numbers up to n, you multiply the thing by k. But this expands your scale by a factor of k, so I divided n by k (automatically being rounded down).
public class Sum {
private static final int n = 15;
public static void main(String[] args) {
int result = compute(3, n) + compute(5, n) - compute(15, n);
System.out.println(result);
}
private static int compute(int k, int n) {
n = n / k;
return k * n * (n + 1) / 2;
}
}
Note:
You can declare your variables inside of the for-loop
You check i < n (n exclusive) instead of i <= n (n inclusive, which I think you want here). If you don't want this, change n = n / k to n = (n - 1) / k.
The task seems pretty easy - on input I get number of tests (numOfTests), then two numbers (downBorder, upBorder) and I have to find how many numbers between those numbers (downBorder, upBorder) are significant numbers where significant number is a number which arithmetic average of proper divisors(all divisors except one and the same number) are smaller or equal than square root of that number.
I wrote the code and probably it works however it's too slow.
My code:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws java.lang.Exception
{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); //faster than Scanner
int numOfTests = Integer.parseInt(bf.readLine());
for(int i = 0; i < numOfTests; i++)
{
String[] borders = bf.readLine().split(" ");
long downBorder = Long.parseLong(borders[0]);
long upBorder = Long.parseLong(borders[1]);
//System.out.println(String.format("down: %s, up: %s", downBorder, upBorder));
System.out.println(countNumberOfSignificantNumbers(downBorder, upBorder));
}
}
/**
* print numbers of significant numbers - (arithmetic average of all divisors that is not bigger than root of that number)
* e.g 4 is significant but 6 is not
* #param downBorder
* #param upBorder
*/
private static int countNumberOfSignificantNumbers(Long downBorder, Long upBorder) {
int numberOfSignificantNumbers = 0;
for(Long i = downBorder; i <= upBorder; i++)
{
if(i%2 != 0)
continue;
else
{
double avgOfProperDivisors = getAvgArithOfSumOfNumberDividers(i);
if(avgOfProperDivisors != 0 && avgOfProperDivisors <= Math.sqrt(i))
numberOfSignificantNumbers++;
}
}
return numberOfSignificantNumbers;
}
/**
* method returns the arithemtic average of all proper divisors (all divisors except one and number itself)
* #param number
* #return
*/
public static double getAvgArithOfSumOfNumberDividers(Long number)
{
long maxD = number/2;
long sum=0;
long numOfDivs = 0;
for(long i = 2; i <= maxD; i++)
{
if(number % i == 0)
{
numOfDivs++;
sum += i;
}
}
return (numOfDivs > 0) ? (double)sum/numOfDivs : 0;
}
}
The bottleneck in this task is counting average of divisors. How can I make it better and faster?
Example input:
2
4 6
1 3
Example output:
1
0
Significant Number will always be a perfect square of a prime number like 4, 9, 25, 49, 121 etc. All you need to check is how many perfect square of a prime numbers lie between upBorder and downBorder.
You can reduce the complexity of the loop from O(number) to O(sqrt(number)).
This is based on the observation that if number is divisible by i, then it is also divisible by number/i. Given this, you can count the two divisors at once; given that the sparsity of the divisors increases as the number increases (i.e. the number of numbers you have to check before finding a divisor), you can save a lot of work in this way.
For example:
for (long i = 2; i*i <= n; ++i) {
if (n % i == 0) {
// i is a divisor, so increment the counters.
numOfDivs++; sum += i;
long c = n / i;
if (c != i) {
// c is a distinct divisor from i, so also increment the counters.
numOfDivs++; sum += c;
}
}
}
For example, 10 = 5*2. This approach finds a divisor when i=2, meaning that c=5. It can stop checking after i=3. In contrast, checking while i<=10/2 will stop checking after i=5.
As the number increases, the difference becomes far greater. For example, with number==1000, you check 499 numbers with i<=1000/2, but just 30 with i*i <= 1000.
I am trying to find the Largest prime factor of a number while solving this problem here. I think that I am doing everything right, however one of the test case (#2) is failing and I can't think of any corner case where it might fail. Here's my code, please have a look and try to spot something.
public class ProblemThree
{
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
int T = scanner.nextInt();
for (int i = 0; i < T; i++)
{
System.out.println(largestPrime(scanner.nextLong()));
}
}
private static long largestPrime(long n)
{
while (n % 2 == 0)
{
n = n / 2; // remove all the multiples of 2
}
while (n % 3 == 0)
{
n = n / 3; // remove all the multiples of 2
}
// remove multiples of prime numbers other than 2 and 3
while (n >= 5)
{
boolean isDivisionComplete = true;
for (long i = 5; i < Math.ceil(Math.sqrt(n)); i++)
{
if (n % i == 0)
{
n = n / i;
isDivisionComplete = false;
break;
}
}
if (isDivisionComplete)
{
break;
}
}
return n;
}
}
Basically, what I am doing is:
Largest_Prime(n):
1. Repeatedly divide the no by any small number, say x where 0 < x < sqrt(n).
2. Then set n = n/x and repeat steps 1 and 2 until there is no such x that divides n.
3 Return n.
It seems you have some bug in your code as as when you input 16 largestPrime function return 1. and this is true for when input is the power of 3.
Detailed Algorithm description:
You can do this by keeping three variables:
The number you are trying to factor (A)
A current divisor store (B)
A largest divisor store (C)
Initially, let (A) be the number you are interested in - in this case, it is 600851475143. Then let (B) be 2. Have a conditional that checks if (A) is divisible by (B). If it is divisible, divide (A) by (B), reset (B) to 2, and go back to checking if (A) is divisible by (B). Else, if (A) is not divisible by (B), increment (B) by +1 and then check if (A) is divisible by (B). Run the loop until (A) is 1. The (3) you return will be the largest prime divisor of 600851475143.
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
for(int a0 = 0; a0 < t; a0++){
long n = in.nextLong();
long A=n;
long B=2;
long C=0;
while(Math.pow(B,2)<=A)
{
if(A%B==0)
{
C=B;
A=A/B;
B=2;
}
else
B++;
}
if(A>=C)
C=A;
if(A==1)
{ C=2;
break;
}
System.out.println(C);
}
}
Why are you removing multiples of 2 and multiples of 3? This way if you have a number that is any combination of powers of 2 and 3 you will get your answer as 1 which is clearly wrong.
For this problem you can do the naive way of looping from 2 to sqrt(n) and store the largest number which divides n, when you finish your loop just return the highest divisor you found.
1 drop your loop for 2 and 3. If not, you dont get 2, 2x2, 3, 2x3, ... all multiples of 2 and 3
2 change your loop to stop at 2 (and not 5):
while (n >= 2)
{
3 stop if 2
if (n==2) return 2;
4 loop from 2
and
5 loop until sqrt(n), with <= and not only < (if not, you dont get prime X Prime)
for (long i = 2; i <= Math.ceil(Math.sqrt(n)); i++)
One easy way of extracting prime factors is like this:
/**
* Prime factors of the number - not the most efficient but it works.
*
* #param n - The number to factorise.
* #param unique - Want only unique factors.
* #return - List of all prime factors of n.
*/
public static List<Long> primeFactors(long n, boolean unique) {
Collection<Long> factors;
if (unique) {
factors = new HashSet<>();
} else {
factors = new ArrayList<>();
}
for (long i = 2; i <= n / i; i++) {
while (n % i == 0) {
factors.add(i);
n /= i;
}
}
if (n > 1) {
factors.add(n);
}
return new ArrayList<>(factors);
}
Those first loops are a problem. They will reduce all even numbers to 1 - thus missing 2 as the factor. Changing your code to use:
while (n > 2 && n % 2 == 0) {
n = n / 2; // remove all the multiples of 2
}
while (n > 3 && n % 3 == 0) {
n = n / 3; // remove all the multiples of 2
}
You still have further issues - e.g. you report the largest prime factor of 25 to be 25 and the largest prime factor of 49 to be 49.
Just run this code using yours and mine to see where yours fails:
for (long i = 1; i < 1000; i++) {
long largestPrime = largestPrime(i);
List<Long> primeFactors = primeFactors(i, true);
if (primeFactors.size() > 0) {
Collections.sort(primeFactors, Collections.reverseOrder());
long highestFactor = primeFactors.get(0);
if (largestPrime != highestFactor) {
System.out.println("Wrong! " + i + " " + largestPrime + " != " + primeFactors);
}
} else {
System.out.println("No factors for " + i);
}
}
In my current Project Euler problem 5, I have a "working" solution. It works on smaller numbers (the example one in the question), but not on the actual problem, because I'm brute forcing it, and the program doesn't finish.
Here's the explanation of the problem:
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest positive number that is evenly divisible1 by all of the numbers from 1 to 20?
1: Divisible with no remainder
Here is my current code:
package Euler;
public class Euler5 {
public static void main(String[] args) {
int desiredNumber = 20;
boolean exitLoop = false;
long counter = 1;
while(exitLoop == false) {
long loopCounter = 0;
for(int i=1; i<=desiredNumber; i++) {
if(counter % i == 0) {
loopCounter++;
}
}
if(loopCounter == desiredNumber) {
exitLoop = true;
System.out.println(counter);
}
counter++;
}
}
}
You don't have a computer to answer this question. Look: if a number can be divided by each of the numbers from 1 to 20 it means that it should be a multiplication of primes in corresponding powers:
2**4 (from 16)
3**2 (from 9)
5
7
11
13
17
19
so the solution is
16 * 9 * 5 * 7 * 11 * 13 * 17 * 19 == 232792560
since the answer is quite large I doubt if brute force is a reasonable method here.
In general case (for some n >= 2) find out all the prime numbers that are not exeeding the n:
2, 3, ..., m (m <= n)
then, for each prime number a find out the power pa such that
a**pa <= n
but
a**(pa + 1) > n
the answer will be
2**p2 * 3**p3 * ... * m**pm
Possible Java implementation:
public static BigInteger evenlyDivisible(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");
else if (n <= 2)
return BigInteger.valueOf(n);
ArrayList<Integer> primes = new ArrayList<Integer>();
primes.add(2);
for (int i = 3; i <= n; i += 2) {
boolean isPrime = true;
for (int p : primes) {
if (i % p == 0) {
isPrime = false;
break;
}
else if (p * p > i)
break;
}
if (isPrime)
primes.add(i);
}
BigInteger result = BigInteger.ONE;
for(int p : primes) {
// Simplest implemenation, check for round up errors however
int power = (int)(Math.log(n) / Math.log(p));
result = result.multiply(BigInteger.valueOf(p).pow(power));
}
return result;
}
...
System.out.println(evenlyDivisible(20)); // 232792560
The number you are seeking is the Least common multiple (LCM) of the numbers 1,2,3,...,20.
By splitting each numbers to the multiplication of its prime factors (easy for small numbers), finding LCM is fairly easy.
Problem 5: 2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
I have solved the problem 5 of Project Euler
Here is the Java code:
static long FindLcm(long a,long b)
{
long lcm,hcf = 0;
long i=1;
long ger=a>b?a:b;
while(i<ger)
{
if((a%i==0) && (b%i==0))
hcf=i;
i++;
}
lcm=(a*b)/hcf;
return lcm;
}
static void FindMultiple()
{
long lcm=1;
for(long i=2;i<=20;i++)
{
lcm=FindLcm(lcm,i);
}
System.out.println("Lcm="+lcm);
}
How can optimize this?
Your FindMultiple() method is not bad,
static void FindMultiple()
{
long lcm=1;
for(long i=2;i<=20;i++)
{
lcm=FindLcm(lcm,i);
}
System.out.println("Lcm="+lcm);
}
it implements a fairly good algorithm. Your problem is that your FindLcm() contains a nasty performance bug.
static long FindLcm(long a,long b)
{
long lcm,hcf = 0;
long i=1;
// This sets ger to max(a,b) - why?
long ger=a>b?a:b;
// This would return a wrong result if a == b
// that never happens here, though
while(i<ger)
{
if((a%i==0) && (b%i==0))
hcf=i;
i++;
}
lcm=(a*b)/hcf;
return lcm;
}
You are looping until you reach the larger of the two arguments. Since the cumulative LCMs grow rather fast, that takes a lot of time. But the GCD (or HCF, if you prefer) of two (positive) numbers cannot be larger than the smaller of the two. So looping only until the smaller of the two arguments is reached makes the number of iterations at most 20 here, do that 19 times (for i = 2, ..., 20), it's a trivial amount of computation.
Changing to
long ger = a < b ? a : b;
while(i <= ger) {
gives me (adding timing code, not measuring the printing):
17705 nanoseconds
Lcm=232792560
So less than 20 microseconds for the computation. We can easily push that below 6 microseconds if we use the euclidean algorithm to find the greatest common divisor,
static long gcd(long a, long b) {
while(b > 0) {
a %= b;
if (a == 0) return b;
b %= a;
}
return a;
}
and below 5 if we directly use the GCD as
lcm *= i/gcd(lcm,i);
in FindMultiple().
You're solution is more or less brute force which is why it's taking so long. We know that 2520 is the lcm of (1,2,...,9,10) which means two useful things: 1.) We can start checking factors at 11 and 2.) The answer is a multiple of 2520.
You're searching for the Greatest Common Divisor (gcd) of the answer and the next number in your sequence (similar to a bubble sort). You could just check to see if your current answer is divisible by the next factor and if not then add your current answer to itself until the answer is divisible by the next factor. For Example:
static long findLCM(long a, long b) {
long lcm = (a>b) ? a : b;
while (lcm % b != 0) {
lcm += a;
}
return lcm;
}
Since we started with lcm = a, we know that as long as we add a's to lcm then lcm will always be divisible by a. Now, we just need to make some multiple of a divisible by b. This process should cut out many steps of first finding the gcd as well as iterating from 2 through 10.
i did it like this, which was the easiest way i could think of. it's also a little faster than yours.
for(int i = 190; ; i += 190) {
if(i % 3 == 0
&& i % 4 == 0
&& i % 6 == 0
&& i % 7 == 0
&& i % 8 == 0
&& i % 9 == 0
&& i % 11 == 0
&& i % 12 == 0
&& i % 13 == 0
&& i % 14 == 0
&& i % 15 == 0
&& i % 16 == 0
&& i % 17 == 0
&& i % 18 == 0
&& i % 20 == 0) {
System.out.println(i);
break;
}
}
Here are 4 different methods to obtain the result (4 different ways to obtain GCD) + the total time. All of them are based on the following observation:
a*b
lcm(a,b) = ----------
gcd(a,b)
where:
LCM = Least Common Multiple
GCD = Greatest Common Divisor
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
public class A {
final static int N = 20;
static Map<Integer, String> messages = new HashMap<>();
static {
messages.put(0, "Euler - difference");
messages.put(1, "modulo - recursive");
messages.put(2, "modulo - iterative");
messages.put(3, "BigInteger implementation");
}
private static long GCD0(long x, long y) {
while (x != y) {
if (x > y) {
x -= y;
} else {
y -= x;
}
}
return x;
}
private static long GCD1(long x, long y) {
if (x % y == 0) {
return y;
}
return GCD1(y, x % y);
}
private static long GCD2(long x, long y) {
long aux;
while (x % y != 0) {
aux = y;
y = x % y;
x = aux;
}
return y;
}
private static long GCD3(long x, long y) {
BigInteger xx = BigInteger.valueOf(x);
BigInteger yy = BigInteger.valueOf(y);
return xx.gcd(yy).longValue();
}
private static void doIt(int pos) throws Exception {
System.out.print("\n" + messages.get(pos));
printSpaces(25, messages.get(pos).length());
Class cls = Class.forName("A");
Object obj = cls.newInstance();
Method method = cls.getDeclaredMethod("GCD" + pos, long.class,
long.class);
long start = System.nanoTime();
long p = 1;
for (int i = 2; i <= N; i++) {
p = (p * i) / (long) method.invoke(obj, p, i);
}
long stop = System.nanoTime();
System.out.println("\tTime: " + (stop - start) / 1000 + " microseconds");
System.out.println(p);
}
private static void printSpaces(int total, int actualLength) {
for (int i = 0; i < total - actualLength; i++) {
System.out.print(" ");
}
}
public static void main(String[] args) throws Exception {
doIt(0);
doIt(1);
doIt(2);
doIt(3);
}
}
Output:
Euler - difference Time: 137205 microseconds
232792560
modulo - recursive Time: 1240 microseconds
232792560
modulo - iterative Time: 1228 microseconds
232792560
BigInteger implementation Time: 2984 microseconds
232792560
P.S.: I used reflection to call those methods easier, but you can call the method directly to obtain a better performance + a better readability.
int i = 20;
while (true)
{
if (
(i % 1 == 0) &&
(i % 2 == 0) &&
(i % 3 == 0) &&
(i % 5 == 0) &&
(i % 7 == 0) &&
(i % 9 == 0) &&
(i % 11 == 0) &&
(i % 13 == 0) &&
(i % 16 == 0) &&
(i % 17 == 0) &&
(i % 19 == 0) )
{
break;
}
i += 20;
}
S.O.P(i);
C++ Program with minimum iteration... very much resemble to Daniel Fischer
#include<iostream>
using namespace std;
int main()
{
int num = 20;
long lcm = 1L;
for (int i = 2; i <= num; i++)
{
int hcf = 1;
for (int j = 2; j <= i; j++)
{
if (i % j == 0 && lcm % j == 0)
{
hcf = j;
}
}
lcm = (lcm * i) / hcf;
}
cout << lcm << "\n";
}
This method uses brute force, but skips as soon as a number fails instead of continuing to compare the remainders. Heck, it never checks for 20 unless 19 has passed already, which actually makes it pretty efficient.
#include<stdio.h>
int a = 1, b = 1, rem;
int main() {
while (b < 20){
rem = a % b;
if (rem != 0){
a++;
b = 1;
}
b++;
}
printf("%d is the smallest positive number divisible by all of the numbers from 1 to 20.", a);
}
A Non Brute Force Method
This one is instantaneous! Doesn't even take a second. Run the code to understand the logic. It's written in C
#include <stdio.h>
int main() {
int primes[8]={2,3,5,7,11,13,17,19};
int primes_count[8]={0,0,0,0,0,0,0,0};
int i,j,num,prime_point;
int largest_num=1;
printf("\nNUM");
for(j=0;j<8;j++)
printf("\t%d",primes[j]);
for(i=2;i<=20;i++) {
num=i;
int primes_count_temp[8]={0,0,0,0,0,0,0,0};
for(j=0;j<8;j++) {
while(num%primes[j]==0) {
num=num/primes[j];
primes_count_temp[j]++;
}
}
for(j=0;j<8;j++)
if(primes_count_temp[j]>primes_count[j])
primes_count[j]=primes_count_temp[j];
printf("\n %d",i);
for(j=0;j<8;j++)
printf("\t %d",primes_count_temp[j]);
}
printf("\nNET");
for(j=0;j<8;j++)
printf("\t%d",primes_count[j]);
printf("\n");
for(i=0;i<8;i++)
while(primes_count[i]) {
largest_num*=primes[i];
primes_count[i]--;
}
printf("The answer is %d \n",largest_num);
return 0;
}
Now if a number is divisible by X it will be divisible by its prime factors also. So if a number is divisible by 20 it will be divisible by its prime factors. And there are 8 prime factors under 20. I take each number under 20 and find its prime factors, also see the power of the prime factor and keep a count of the highest power.
Once you're done. Multiply all the prime factors raised to their highest power.
my Solution for this in python. this is so simple and use pure Math rules
get the Least Common Multiple
def getLCM (x, y):
return x*y/getGCD(x,y)
get the Greatest Common Divisor
def getGCD(a,b):
while(True):
if(a%b != 0):
temp = b
b = a%b
a = temp
else:
return b
break
Find the Least Common Multiple of, LCM of prev two numbers and next number in list.
LCM(LCM of prev two numbers,next number in list)
num_list = list(range(1,21))
finalLCM = 1
for i in num_list:
finalLCM = getLCM(finalLCM,i)
print(finalLCM)
Full Python Code
def getLCM (x, y):
return x*y/getGCD(x,y)
def getGCD(a,b):
while(True):
if(a%b != 0):
temp = b
b = a%b
a = temp
else:
return b
break
num_list = list(range(1,21))
finalLCM = 1
for i in num_list:
finalLCM = getLCM(finalLCM,i)
print(finalLCM)
we have create an array which was common divisible eg: if any number is divisible by 20 then no need to divisible by 2,4,5,10
<?php
$chk=20;
$div=array(11,12,13,14,15,16,17,18,19,20);
for($number=1;1;$number++){
$chk=$number;
foreach($div as $value){
if($number%$value!=0){
$chk=0;
$number+=$value;
break;
}
}
if($chk!=0){break;}
}
echo $chk;
?>