Largest Divisor of N (Excluding Itself) - java

I'm trying to divide a list into sublists that are as large as possible. If the list can not be divided in such a way, I will handle it as needed, but I need get the largest number besides N itself that divides N evenly.
I wrote a really naive solution, but I feel like there should be maybe a formula or something to do this in constant time. My list are not that big, maximum size is 1000. This probably isn't the critical path, but is there a better algorithm?
public static int largestDivisor(int n){
int divisor = 0;
for (int i = 1; i <= n/2; i++)
if (n % i == 0)
divisor = i;
return divisor;
}

Iterate the values in reverse. Simply return the first one you find (it'll be the greatest). Something like,
public static int largestDivisor(int n) {
for (int i = n / 2; i >= 2; i--) {
if (n % i == 0) {
return i;
}
}
return 1;
}
Alternatively, you might make a slight improvement to #WillemVanOnsem's answer and start with odd values like;
public static int largestDivisor(int n) {
if (n % 2 == 0) {
return n / 2;
}
final int sqrtn = (int) Math.sqrt(n);
for (int i = 3; i <= sqrtn; i += 2) {
if (n % i == 0) {
return n / i;
}
}
return 1;
}

I don't know if you can do this in constant time, but you can certainly do it in less time than this.
Start with 2, and loop through all numbers, checking if n is divisible by that number. When you get to a number that divides n, then you can stop - your answer is n/i. If you get to the end and it still doesn't divide, then n is prime and the answer is just 1.
Instead of ending at n/2 if you don't find a divisor, you can end at √n with this method, which will reduce the big O.
Also, you could start with checking if it's divisible by 2, then go to 3 and only check the odd numbers from there. (If it was divisible by an even number, then it was divisible by 2.) That won't change the big O, but it should cut the processing time almost in half since you're only checking about half the divisors.

You know that if a is dividable by b, it is also dividable by a/b and the smaller b is, the larger is a/b, so once you have found the divisor, return n/divisor:
public static int largestDivisor(int n){
for(int i = 2; i <= n/2; i++)
if(n % i == 0) {
return n/divisor;
}
}
return 0; //or whatever you decide to return if there is no such divisor
}
This is also faster because:
divisors tend to become more rare the larger they get; and
you can already give up at sqrt(n).
So the most efficient approach would be:
public static int largestDivisor(int n){
int sqrtn = (int) Math.sqrt(n);
for(int i = 2; i <= sqrtn; i++)
if(n % i == 0) {
return n/divisor;
}
}
return 0;
}

Related

Program to sum the odd digits recursively

Using recursion, If n is 123, the code should return 4 (i.e. 1+3). But instead it is returning the last digit, in this case 3.
public static int sumOfOddDigits(NaturalNumber n) {
int ans = 0;
if (!n.isZero()) {
int r = n.divideBy10();
sumOfOddDigits(n);
if (r % 2 != 0) {
ans = ans + r;
}
n.multiplyBy10(r);
}
return ans;
}
It isn't clear what NaturalNumber is or why you would prefer it to int, but your algorithm is easy enough to follow with int (and off). First, you want the remainder (or modulus) of division by 10. That is the far right digit. Determine if it is odd. If it is add it to the answer, and then when you recurse divide by 10 and make sure to add the result to the answer. Like,
public static int sumOfOddDigits(int n) {
int ans = 0;
if (n != 0) {
int r = n % 10;
if (r % 2 != 0) {
ans += r;
}
ans += sumOfOddDigits(n / 10);
}
return ans;
}
One problem is that you’re calling multiplyBy on n and not doing anything with the result. NaturalNumber seems likely to be immutable, so the method call has no effect.
But using recursion lets you write declarative code, this kind of imperative logic isn’t needed. instead of mutating local variables you can use the argument list to hold the values to be used in the next iteration:
public static int sumOfOddDigits(final int n) {
return sumOfOddDigits(n, 0);
}
// overload to pass in running total as an argument
public static int sumOfOddDigits(final int n, final int total) {
// base case: no digits left
if (n == 0)
return total;
// n is even: check other digits of n
if (n % 2 == 0)
return sumOfOddDigits(n / 10, total);
// n is odd: add last digit to total,
// then check other digits of n
return sumOfOddDigits(n / 10, n % 10 + total);
}

How to optmize the method

I have been solving a problem in hackerrank. I am sure my solution is right but as the input matrix gets large the program terminates due to time out.
I have a method where i find a series given below. This method takes array index numbers and computes a number based on the method. Based on the number, i fill up my array with something. But the program terminates every time. It only works with for maximum n=2. I think this method should be optimized because it uses huge recursion for large n. Is there any suggestion what should i do ?
static int hacko(int n)
{
if(n==1)
return 1;
else if(n==2)
return 2;
else if(n==3)
return 3;
else
return hacko(n-1)+(2*hacko(n-2))+(3*hacko(n-3));
}
You could avoid unnecessary branches, which can be costly, like this:
static int hacko(int n) {
if(n < 4)
return n;
else
return hacko(n-1)+(2*hacko(n-2))+(3*hacko(n-3));
}
I assume n > 0, otherwise use if(n > 0 && n < 4). However, you stated:
It only works with for maximum n=2.
So the method you posted is most likely not the bottleneck, since n=3 does not add any significant complexity to the code compared to n=1 or n=2. Or what do you mean by this?
As recursion is not a requirement for you, you can do the following iterative approach:
static int hacko(int n) {
// Shortcut for n=1, n=2 and n=3
if (n < 4)
return n;
// Array to store the previous results
int[] temp = new int[n];
temp[0] = 1;
temp[1] = 2;
temp[2] = 3;
// Iterative approach, more scalable, counts up
for (int i = 3; i < n; i++) {
temp[i] = 3 * temp[i - 3] + 2 * temp[i - 2] + temp[i - 1];
}
return temp[n - 1];
}
The problem here is, for large values of n, it calculates hacko(n-1)+(2*hacko(n-2))+(3*hacko(n-3)) recursively. This can be time consuming and unnecessary.
You can optimize it by saving values of hackos(i) in an array and fetching the values of hacko(n-1)+(2*hacko(n-2))+(3*hacko(n-3)) from the array and not calculating it recursively everytime. U need to start the loop from i=1 to i=N
Ex:
int savedData[] = new int[N];
static int hacko(int n)
{
if(n==1)
return 1;
else if(n==2)
return 2;
else if(n==3)
return 3;
else
return savedData[n-1]+(2*savedData[n-2])+(3*savedData[n-3]);
}
for(int i=1;i<N;i++) {
savedData[i] = hacko(i);
}
Hope it Helps.

Trailing Zeroes of a Factorial

I'm trying to solve this coding question:
Given an integer n, return the number of trailing zeroes in n!
Below is my code (codec this up using the wiki link)
public int trailingZeroes(int n) {
int count = 0, i = 5;
while(i<=n){
count+= n/i;
i*=5;
}
return count;
}
This runs for all test cases except when n = Integer.MAX_VALUE upon which I get a TLE. How can I fix this code to make it cover that test case. I have read about five articles on the net and everything seems to agree with my approach.
Much thanks.
So, I followed the long/BigInteger approach (thanks y'all):
public int trailingZeroes(int n) {
long count = 0;
for(long i= 5; n/i >= 1; i= i*5){
count+= n/i;
}
return (int)count;
}
As Iaune observed, your loop will never terminate when n is Integer.MAX_VALUE, because there is no int greater than that number (by definition). You should be able to restructure your loop to avoid that problem. For instance, this is the same basic approach, but flipped upside-down:
public int trailingZeroes(int n) {
int count = 0;
while (n > 0) {
n /= 5;
count += n;
}
return count;
}
You cannot write a for or while loop where the loop counter is an int and the upper limit is <= Integer.MAX_VALUE.
What happens with a simple increment (counter++) is that the loop counter is set to that value, the body executes and then the counter is incremented which results in a negative number, Integer.MIN_VALUE. And then everything happens all over again.
Other weird things may happen when the loop counter is incremented in quantities > 1 or (as here) is multiplied: the int loop counter just can't hold a value > Integer.MAX_VALUE
Consider another approach for iterating over these numbers. Or handle MAX_VALUE separately.
Your problem is that once i gets large enough (more than Integer.MAX_INT / 5) then the line i*=5; causes i to overflow to the "wrong" value. The value in question is 5 to the 14th power, which is 6103515625, but which overflows to 1808548329.
The result of this is that the loop just keeps executing forever. i will never become a value that's not <= Integer.MAX_INT, because there's just no such int.
To avoid this, you need i to be a larger data type than an int. If you change i and count in your original code to long, this will work fine. Of course, BigInteger would also work.
public class FactorialNumberTrailingZeros {
public static void main(String[] args) {
System.out.println(trailingZeroes(1000020));
}
private static int trailingZeroes(int n) {
int count = 0;
while (n > 0 && (n % 10 == 0)) {
n /= 10;
count ++;
}
return count;
}
}
public static void main(String[] args) {
int result = findFactorialTrailingZero(100);
System.out.println("no of trailing zeros are " + result);
}
public static int findFactorialTrailingZero(int no) {
int zeros = no / 5;
int zeroIncrementNo = 25;
int zerosIncrementFactor = 1;
int nextZeroIncrenent = 5;
for (int i = 1;no >= zeroIncrementNo; i++) {
zeros=zeros+zerosIncrementFactor;
zeroIncrementNo=25*(i+1);
if(i+1==nextZeroIncrenent){
zerosIncrementFactor++;
nextZeroIncrenent=nextZeroIncrenent*5;
}
}
return zeros;
/*
[n/5]+[n/25]+[n/125]+....
if n<25 then [n/5]
if n<125 then [n/5]+[n/25]
if n<625 then [n/5]+[n/25]+[n/125]
*/
#include<bits/stdc++.h>
#include<iostream>
using namespace std;
int countTrailingZeroes(int n)
{
int res=0;
for(int i=5;i<=n;i=i*5){
res=res+n/i;
}
return res;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n;
cin>>n;
cout<<countTrailingZeroes(n);
return 0;
}
Output
25
6
Explanation:
25!=1.551121e+25 i.e contains 6 trailing zeroes
Here is my python code that could solve your problem:
def check(n):
j,ans=5,0
while j<=n:
ans=ans+n//j
j=j*5
return ans

Very simple prime number test - I think I'm not understanding the for loop

I am practicing past exam papers for a basic java exam, and I am finding it difficult to make a for loop work for testing whether a number is prime. I don't want to complicate it by adding efficiency measures for larger numbers, just something that would at least work for 2 digit numbers.
At the moment it always returns false even if n IS a prime number.
I think my problem is that I am getting something wrong with the for loop itself and where to put the "return true;" and "return false;"... I'm sure it's a really basic mistake I'm making...
public boolean isPrime(int n) {
int i;
for (i = 2; i <= n; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
The reason I couldn't find help elsewhere on stackoverflow is because similar questions were asking for a more complicated implementation to have a more efficient way of doing it.
Your for loop has a little problem. It should be: -
for (i = 2; i < n; i++) // replace `i <= n` with `i < n`
Of course you don't want to check the remainder when n is divided by n. It will always give you 1.
In fact, you can even reduce the number of iterations by changing the condition to: - i <= n / 2. Since n can't be divided by a number greater than n / 2, except when we consider n, which we don't have to consider at all.
So, you can change your for loop to: -
for (i = 2; i <= n / 2; i++)
You can stop much earlier and skip through the loop faster with:
public boolean isPrime(long n) {
// fast even test.
if(n > 2 && (n & 1) == 0)
return false;
// only odd factors need to be tested up to n^0.5
for(int i = 3; i * i <= n; i += 2)
if (n % i == 0)
return false;
return true;
}
Error is i<=n
for (i = 2; i<n; i++){
You should write i < n, because the last iteration step will give you true.
public class PrimeNumberCheck {
private static int maxNumberToCheck = 100;
public PrimeNumberCheck() {
}
public static void main(String[] args) {
PrimeNumberCheck primeNumberCheck = new PrimeNumberCheck();
for(int ii=0;ii < maxNumberToCheck; ii++) {
boolean isPrimeNumber = primeNumberCheck.isPrime(ii);
System.out.println(ii + " is " + (isPrimeNumber == true ? "prime." : "not prime."));
}
}
private boolean isPrime(int numberToCheck) {
boolean isPrime = true;
if(numberToCheck < 2) {
isPrime = false;
}
for(int ii=2;ii<numberToCheck;ii++) {
if(numberToCheck%ii == 0) {
isPrime = false;
break;
}
}
return isPrime;
}
}
With this code number divisible by 3 will be skipped the for loop code initialization.
For loop iteration will also skip multiples of 3.
private static boolean isPrime(int n) {
if ((n > 2 && (n & 1) == 0) // check is it even
|| n <= 1 //check for -ve
|| (n > 3 && (n % 3 == 0))) { //check for 3 divisiable
return false;
}
int maxLookup = (int) Math.sqrt(n);
for (int i = 3; (i+2) <= maxLookup; i = i + 6) {
if (n % (i+2) == 0 || n % (i+4) == 0) {
return false;
}
}
return true;
}
You could also use some simple Math property for this in your for loop.
A number 'n' will be a prime number if and only if it is divisible by itself or 1.
If a number is not a prime number it will have two factors:
n = a * b
you can use the for loop to check till sqrt of the number 'n' instead of going all the way to 'n'. As in if 'a' and 'b' both are greater than the sqrt of the number 'n', a*b would be greater than 'n'. So at least one of the factors must be less than or equal to the square root.
so your loop would be something like below:
for(int i=2; i<=Math.sqrt(n); i++)
By doing this you would drastically reduce the run time complexity of the code.
I think it would come down to O(n/2).
One of the fastest way is looping only till the square root of n.
private static boolean isPrime(int n){
int square = (int)Math.ceil((Math.sqrt(n)));//find the square root
HashSet<Integer> nos = new HashSet<>();
for(int i=1;i<=square;i++){
if(n%i==0){
if(n/i==i){
nos.add(i);
}else{
nos.add(i);
int rem = n/i;
nos.add(rem);
}
}
}
return nos.size()==2;//if contains 1 and n then prime
}
You are checking i<=n.So when i==n, you will get 0 only and it will return false always.Try i<=(n/2).No need to check until i<n.
The mentioned above algorithm treats 1 as prime though it is not.
Hence here is the solution.
static boolean isPrime(int n) {
int perfect_modulo = 0;
boolean prime = false;
for ( int i = 1; i <= n; i++ ) {
if ( n % i == 0 ) {
perfect_modulo += 1;
}
}
if ( perfect_modulo == 2 ) {
prime = true;
}
return prime;
}
Doing it the Java 8 way is nicer and cleaner
private static boolean isPrimeA(final int number) {
return IntStream
.rangeClosed(2, number/2)
.noneMatch(i -> number%i == 0);
}

Making solution for Project Euler more efficient

Originally, I was having some issues getting this code to function, but after a little tweaking I got it debugged and ready to go.
I have gone through several revisions of this program. I started with integer values only to find that the number was too large to fit into an int. I then changed to BigIntegers, which proved to be a hassle, but workable. From there, I switched to longs (as should have done from the beginning) and cut the runtime of my code 8-fold (or more).
Here's the code as it is now:
long qNum = 600851475143L;
for (long i = qNum - 1L; i * i >= qNum; i -= 2L)
if (qNum % i == 0 && isPrime(i)) {
System.out.println("Solution:" + i); // for debugging
return i;
}
else
System.out.println(i);// for debugging
return 0L;
And
public static boolean isPrime(long num) {
// unnecessary if statement for this problem (b/c of for loop), but useful for others
if (num % 2 == 0)
return false;
for (long i = 3; i * i <= num; i += 2)
if (num % i == 0)
return false;
return true;
}
It's been running for multiple hours and it still hasn't found anything. I saw online that solving this puzzle the typical way is like parsing 560GB of data =/.
Any tips for speeding this up?
Many thanks,
Justian
EDIT:
Optimized code:
public static long greatestPrimeFactor(ArrayList<Long> factors, long num) {
for (long i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
factors.add(i);
return greatestPrimeFactor(factors, num / i);
}
}
for (int i = factors.size()-1; i > 0; i--)
if (isPrime(factors.get(i)))
return num;
return 0;
}
AND
public static boolean isPrime(long num) {
if (num % 2 == 0)
return false;
for (long i = 3; i * i <= num; i += 2)
if (num % i == 0)
return false;
return true;
}
RUN WITH
greatestPrimeFactor(new ArrayList<Long>(), 600851475143L);
My solution hits in less than a hundredth of a second. Each time you find a divisor of the number, divide the number by that divisor and start again. The highest number you divide by is your target.
You are doing too many unnecessary things. Here's a simpler solution:
long greatestFactor(long n) {
long p = 0;
for (long k = 2; k * k <= n; k++)
while (n % k == 0) {
n /= k;
p = k;
}
if (n > 1)
p = n;
return p;
}
You don't need to test every number for whether or not it is prime. You see this, so you only test every ODD number (well, and 2). You can take this further! Construct a table of the first few million primes quickly, and only test against those. You'll go a LOT faster, with a very small overhead.
Edit: Here's what I was talking about. It's quite straightforward. Notice how I only compare the values to already computed primes. Once you've computed a fair number of them (say, the first 10000000 primes) start doing your search based on on the +2 method like you are. Keep in mind that most of them are going to get caught early because you're skipping unnecessary numbers. You don't need to test 15,25,35,45,55, etc, because you already tested 5. That in and of itself is going to cull about 20% of your tests, which easily accounts for the overhead of calculating the first few million numbers.
Sample output
C:\files\j\misc>java sandbox2
resized to 200
resized to 400
resized to 800
resized to 1600
resized to 3200
resized to 6400
resized to 12800
resized to 25600
resized to 51200
resized to 102400
resized to 204800
resized to 409600
resized to 819200
664579 primes in 18 seconds. Last prime was 9999991
C:\files\j\misc>
Sample code:
public class sandbox2 {
static int[] primes = new int[100]; // where the primes really are
static int count = 0;
static long mostRecentPrime;
public static void main(String[] args) throws Exception {
addPrime(2); // give it a couple to start
addPrime(3);
addPrime(5);
long start = System.currentTimeMillis();
for(long i = 7; i < 10000000; i++) { // all primes less than 10M
if(isPrime(i)) addPrime(i);
}
long end = System.currentTimeMillis();
long time = (end-start) / 1000;
System.out.println(count + " primes in " + time + " seconds. Last prime was " + mostRecentPrime);
}
public static boolean isPrime(long i) {
long max = (long)(Math.sqrt(i))+1;
for(int pos = 0; primes[pos] < max && pos < primes.length; pos++) {
long prime = (long)(primes[pos]);
if(i % prime == 0) return false;
}
return true;
}
public static void addPrime(long p) {
mostRecentPrime = p;
if(count == primes.length) { // resize if necessary
int size = primes.length * 2;
int[] newprimes = new int[size];
System.arraycopy(primes, 0, newprimes, 0, primes.length);
primes = newprimes;
System.out.println("resized to " + primes.length);
}
primes[(int)count] = (int)p;
count++;
}
}
In python, you can just calculate all the prime factors and then use the max function, like so:
def calc_prime_factors(n,i=2,result=[]):
while i<=n:
while n%i!=0:
i+=1
result.append(i)
if n!=1:
n,i=n/i,2
else:
break
return result
print max(calc_prime_factors(600851475143))

Categories

Resources