I have an array of integer numbers, my task is to get the last 2 digits after multiplying all these numbers.
I have come up with the below code:
static void process(int array[]) {
if (array.length <= 0) {
System.out.println("-1");
return;
}
int answer = array[0] % 100;
for (int i = 1; i < array.length; i++) {
answer = (answer * array[i] % 100) % 100;
}
System.out.println(answer);
}
I felt this is a better approach, but when I used this during one my exams it passed only 2 out of 4 test cases. The test cases failed due to performance issues. The failed test cases were hidden, so not able to see them.
I even tried the alternate approach like initializing a long variable to 1 then using a for loop and multiplying the long variable with array element. Finally getting the last two digits from long variable, even that failed with 2 test cases.
Is there any better approach to solve this problem.
There are some potential shortcuts. Multiplying by a number ending in 0 or two numbers ending in 2 and 5 respectively would guarantee the last digit is a 0. Doing that twice makes your last two digits 00 and you can print the result early. You could check whether your answer is 00 and break out of the loop if that happens.
This would slow down your algorithm against data that is tailored against this check. However, a large (>1000) randomized set of numbers would be be almost guaranteed to end in 00 early and be faster than your initial approach.
Sample code:
static void process(int array[]) {
if (array.length <= 0) {
System.out.println("-1");
return;
}
int answer = array[0] % 100;
for (int i = 1; i < array.length; i++) {
if(answer == 0) {
break;
}
answer = (answer * array[i] % 100) % 100;
}
System.out.println(answer);
}
Are you sure that it is due to performance issues? If yes, then I think it is kind of a stupid question, because O(n) is the best you can get.
My guess is that it was because your answer wasn't correct. E.g. if your answer is "1", then it could actually be "01". So a correct implementation would take that into account.
boolean atLeast10 = false;
int answer = 1;
int i = 0;
for (; i < array.length && !atLeast10; i++) {
if (array[i] == 0) {
System.out.println(0);
return;
}
answer = answer * array[i];
if (answer >= 10)
atLeast10 = true;
}
answer = answer % 100;
for (; i < array.length; i++) {
if (array[i] == 0) {
System.out.println(0);
return;
}
answer = (answer * array[i] % 100) % 100;
}
if (!atLeast10 || answer >= 10)
System.out.println(answer);
else
System.out.println("0" + answer);
Btw. shortcut is only possible if an element is 0, this is again because even if the number ends in "00" there could follow a 0 much later in the array and then the answer is "0" and not "00", although I like the idea.
Related
How can I optimize this code.
I want to reduce lines of code.
public class CoolDude {
public static void main(String[] args) {
for(int i = 100; i <= 500; ++i) {
if(i%5 == 0 && i%11 == 0) {
System.out.print("Cool Dude- ");
System.out.print(i + "\n");
} else if (i%5 == 0) {
System.out.print("Cool - ");
System.out.print(i + "\n");
} else if (i%11 == 0) {
System.out.print("Dude - ");
System.out.print(i + "\n");
}
}
}
}
Is there any way ?
While Stephen M Irving's answer is pretty spot on and corrects all the beliefs found in your question, this still answers your question, trying to minimize the number of statements.
public class CoolDude {
public static void main(String[] args) {
for (int i = 100; i <= 500; i++)
if (i % 5 == 0 || i % 11 == 0) // This is the condition where we decide to print something
System.out.printf("%s%s- %d%n", i % 5 == 0 ? "Cool " : "", i % 11 == 0 ? "Dude " : "", i);
}
}
However, this code duplicates one of the most expensive part: the modulo. Also, this solution is not readable !
When trying to figure solutions is useful to try several KPI and then find the best to optimize. In this case, you wanted to optimize the number of lines, it's definitely not the best as you can see above. If anything try first to get a working solution then a readable one and finally an optimized one where you document why it's optimized so that the readability is maintained.
Here, for instance, is the most optimized version I could come up with. It definitely contains more lines, but also is definitely faster, since I skip all invalid numbers and never do a modulo (only two divisions and two multiplications for the whole program).
public class CoolDude {
public static void main(String[] args) {
final int min = 100;
final int max = 500;
for (int i5 = nextMultiple(min, 5), i11 = nextMultiple(min, 11); i5 <= max || i11 <= max; ) {
if (i5 < i11) {
System.out.printf("Cool - %d%n", i5);
i5 += 5;
} else if (i11 < i5) {
System.out.printf("Dude - %d%n", i11);
i11 += 11;
} else { // i5 == i11
System.out.printf("Cool Dude - %d%n", i5);
i5 += 5;
i11 += 11;
}
}
}
static int nextMultiple(int number, int divisor) {
int roundToLower = (number - 1) / divisor * divisor;
return roundToLower + divisor;
}
}
You could restructure your decision tree such that there will only ever have to be 2 checks (each with 1 operation and 1 comparison) against the number in the loop. Currently, your decision tree requires 2 operations and 2 comparisons in the best case (i is divisible by both 5 and 11) and 4 operations and 4 comparisons in the worst case (i is not divisible by either 5 or 11), but we can reduce that to always be just 2 comparisons and 2 operations, which will result in a more performant loop. In this way, i is only ever tested for divisibility against 5 and 11 one time for each number, so only 2 operations and 2 comparisons will need to be done no matter what the stage of the loop. This is the sort of optimization you should be looking at when trying to optimize a loop.
I also made your print method calls a printf call instead, reducing two print statements into 1. Here is a printf cheat sheet that you can use if you are unfamiliar with it.
Now, doing all this only reduced the size of your code by 1 line, and while I am sure that could be reduced further with some clever use of ternary operators or other methods, as a general rule, measuring code quality by number of lines is a terrible metric, and should never be used, particularly when we are talking about a compiled language like Java. There are a lot of things I could do to the code below that would reduce the line count at the expense of readability and/or performance, but there is no real point to that outside of competitions between programmers, like code golf (but even with that you are competing for the lowest character count, not line count).
Instead of shooting for shorter code, you should instead be striving for the best Big-O notation complexity so that your code is more performant, and fewer lines of code does not necessarily correlate with performance.
public class CoolDude {
public static void main(String[] args) {
for (int i = 100; i <= 500; ++i) {
if (i % 5 == 0) {
if (i % 11 == 0) {
System.out.printf("Cool Dude - %d\n", i);
} else {
System.out.printf("Cool - %d\n", i);
}
} else if (i % 11 == 0) {
System.out.printf("Dude - %d\n", i);
}
}
}
}
IntStream.rangeClosed(100,500).forEach(i->{
if(i%5 == 0 && i%11 == 0) {
System.out.println("Cool Dude - "+i );
} else if (i%5 == 0) {
System.out.println("Cool - "+i );
} else if (i%11 == 0) {
System.out.println("Dude - "+i );
}
});
The below should reduce lines of code, though it does not appear to run faster. It also corrects spacing around the hyphen and perhaps simplifies the logic.
public class CoolDude {
public static void main(String args[]) {
for (int i = 100; i <= 500; ++i) {
StringBuilder coolDude = new StringBuilder(15); //15 chars max "Cool Dude - 495"
if (i % 5 == 0) {
coolDude.append("Cool ".toCharArray());
}
if (i % 11 == 0) {
coolDude.append("Dude ".toCharArray());
}
if (coolDude.length() > 0) {
System.out.println(coolDude.append(("- " + i).toCharArray()));
}
}
}
}
REVISION:
My point was that it was possible to take advantage of being able to do each mod calculation only once each time through the loop. That got lost in trying to save time with StringBuilders and a single line (which, as others pointed out, isn't a worthy goal). I clarified by using print and println instead.
public class CoolDude {
public static void main(String args[]) {
boolean printed = false;
for (int i = 100; i <= 500; ++i, printed = false) {
if (i % 5 == 0) {
System.out.print("Cool ");
printed = true;
}
if (i % 11 == 0) {
System.out.print("Dude ");
printed = true;
}
if (printed) {
System.out.println("- " + i);
}
}
}
}
The code works correctly until I give it a big value - it takes too much time to execute.
Can you give me some advice how to optimize it?
BigInteger type of n parameter is a must, it's a part of the task ;)
public static String oddity(BigInteger n) {
List<BigInteger> list = new ArrayList<BigInteger>();
String result = null;
for (BigInteger bi = BigInteger.valueOf(1);
bi.compareTo(n) <= 0;
bi = bi.add(BigInteger.ONE)) {
if (n.mod(bi).equals(BigInteger.ZERO))
list.add(bi);
}
if (list.size() % 2 == 0)
result = "even";
else result = "odd";
return result;
}
The purpose of this is to return 'odd' if the number of "n" divisors is odd. Otherwise return 'even'.
Thinking rather than just programming would help a lot. You don't need to find all divisors. You don't even need to count them. All you need is to find out if the count is odd.
But divisors always come in pairs: For every divisor i also n/i is a divisor.
So the count is always even, except when there's a divisor i equal to n/i. Use Guava sqrt ...
As you don't use the list except to get its final size, you could use an integer as a counter, i.e: do n++ instead of list.add(bi).
This is going to save huge amount of memory. Hence save time used to manage its allocation.
// Lambda
long counter = IntStream
.range(1, (int) Math.sqrt(n.longValue())+1)
.filter(i -> n.longValue() % i == 0 && n.longValue() / i == i)
.count();
return (counter % 2 == 0) ? "even" : "odd";
int counter = 0;
for (long i = 1; i <= Math.sqrt(n.longValue()); i++) {
if(n.longValue() % i == 0 && n.longValue()/ i == i){
counter++;
}
}
return (counter % 2 == 0) ? "even" : "odd";
I am writing a Java program that calculates the largest prime factor of a large number. But I have an issue with the program's complexity, I don't know what has caused the program to run forever for large numbers, it works fine with small numbers.
I have proceeded as follow :
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Largest_prime_factor {
public static void main(String[] args)
{
//ArrayList primesArray = new ArrayList();
ArrayList factorArray = new ArrayList();
long largest = 1;
long number = 600851475143L ;
long i, j, k;
//the array list factorArray will have all factors of number
for (i = 2; i < number; i++)
{
if( number % i == 0)
{
factorArray.add(i);
}
}
Here, the Array List will have all the factors of the number.
So I'll need to get only the prime ones, for that, I used a method that checks if a number is prime or not, if it's not a prime number, I remove it from the list using the following method :
java.util.ArrayList.remove()
So the next part of the code is as follow :
for (i = 2; i < number; i++)
{
if (!isPrime(i))
{
factorArray.remove(i);
System.out.println(factorArray);
}
}
System.out.println(Collections.max(factorArray));
}
The last line prints the largest number of factorArray, which is what I am looking for.
public static boolean isPrime(long n)
{
if(n > 2 && (n & 1) == 0)
return false;
for(int i = 3; i * i <= n; i += 2)
if (n % i == 0)
return false;
return true;
}
}
The function above is what I used to determine if the number is a prime or not before removing it from the list.
This program works perfectly for small numbers, but it takes forever to give an output for large numbers, although the last function is pretty fast.
At first, I used to check if a number is prime or not inside of the first loop, but it was even slower.
You are looping over 600851475143 numbers.
long number = 600851475143L ;
for (i = 2; i < number; i++)
Even if we assume that each iteration takes very very small time (as small as 1 microsecond), it'll still take days before the loop finishes.
You need to optimise your prime-finding logic in order for this program to run faster.
One way to reduce the iterations to reasonable number is to loop until square root of number.
for (i = 2; i < Math.sqrt(number); i++)
or
for (i = 2; i*i < number; i++)
The calculation of the prime factors of 600851475143L should take less than a milli-second (with a not totally inefficient algorithm). The main parts your code is currently missing:
The border should be sqrt(number) and not number.
The current value should be checked in a while-loop (to prevent that non-prime-factors are added to the list, reduces range to check).
The max. value should be decreased (as well as the border) to number/factor after finding a factor.
Further improvements are possible, e.g. to iterate only over non-even numbers (or only iterate over numbers that are neither a multiple of 2 and 3) etc.
An example implementation for the same question on codereview (link):
public static long largestPrimeFactor(
final long input) {
////
if (input < 2)
throw new IllegalArgumentException();
long n = input;
long last = 0;
for (; (n & 1) == 0; n >>= 1)
last = 2;
for (; n % 3 == 0; n /= 3)
last = 3;
for (long v = 5, add = 2, border = (long) Math.sqrt(n); v <= border; v += add, add ^= 6)
while (n % v == 0)
border = (long) Math.sqrt(n /= last = v);
return n == 1 ? last : n;
}
for (i = 2; i < number; i++)
{
if( number % i == 0)
{
factorArray.add(i);
}
}
For an large input size, you will be visiting up to the value of the number. Same for the loop of removing factors.
long number = 600851475143L ;
this is a huge number, and you're looping through this twice. Try putting in a count for every 10,000 or 100,000 (if i%10000 print(i)) and you'll get an idea of how fast it's moving.
One of the possible solutions is to only test if the the prime numbers smaller than the large number divide it.
So I checked
for (i=2; i < number; i++)
{
if(isPrime(i))
{
if( number % i == 0)
{
factorArray.add(i);
}
}
}
So here I'll only be dividing by prime numbers instead of dividing by all numbers smaller than 600851475143.
But this is still not fast, a complete modification of the algorithm is necessary to obtain an optimal one.
#Balkrishna Rawool suggestion is the right way to go. For that I would suggest to change the iteration like this: for (i = 3; i < Math.sqrt(number); i+=2) and handle the 2 manually. That will decrease your looping because none of the even numbers except 2 are prime.
I was trying to make a method to do the prime factorization of a number, and it's probably not the most efficient, but I don't see why it shouldn't work.
public static ArrayList<Integer> primeFactorize(int num) {
ArrayList<Integer> primeFactors = new ArrayList<Integer>();
for (int i = 2; i < Math.sqrt((double) num); i++) {
if (isPrime(i) && factor(num).contains(i)) {
primeFactors.add(i);
num /= i;
if (isPrime(num)) {
primeFactors.add(num);
break;
}
i = 2;
}
}
return primeFactors;
}
It calls upon two other methods that I wrote named factor() and isPrime(), which do exactly what you would expect them to (returns an ArrayList of factors and either true or false depending on if the input is prime, respectively).
I went through the debugger with num being 12, and it worked fine for the first loop, where it added 2 to primeFactors. However, when it got to the top of the array again with num being 6 and i being 2, it exited the loop as if i < Math.sqrt((double) num) returned false.
But that wouldn't make sense, because the square root of 6 is a bit over 2. I also tried (double) i < Math.sqrt((double) num), but it just did the same exact thing.
Can anyone see what I'm missing? Thanks for any replies.
EDIT: Here is my code now, thanks for the help! I know for sure I could make it more efficient, so I might do that later, but for now this is perfect.
public static ArrayList<Integer> primeFactorize(int num) {
ArrayList<Integer> primeFactors = new ArrayList<Integer>();
int i = 2;
while (i < Math.sqrt((double) num)) {
if (isPrime(i) && num % i == 0) {
primeFactors.add(i);
num /= i;
if (isPrime(num)) {
primeFactors.add(num);
break;
}
i = 2;
}
else
i++;
}
return primeFactors;
}
In your for loop, the i++ section will get called at the end of every loop. So in your code, you set i equal to 2. Then, the loop ends, and adds 1 to i, making it be 3. Then the comparison happens, and 3 is more than sqrt(6), so the loop exits.
If you want i to be 2 in the next iteration, you need to set it to a value so that after the increment operation runs it will be 2, not before; in this case, you should set it to 1. A better solution would be to change your code structure so it's not necessary though. As pointed out by biziclop, a while loop will let you decide whether or not to increment, and will avoid this problem.
Since you already accepted an answer I assume your problem is solved. The thing I want to point out is that casting integers to doubles is generally a bad idea if there is another way. Therefore I want to show you the below implementation, which doesn't use floating-point arithmetic. Also I think it's a bad idea to check whether or not num is a prime number, because this slows down the algorithm. Moreover if num % i == 0 evaluates to true, i is always a prime number, thus the isPrime(i) check is superfluous and also slows down your algorithm.
List <Integer> primeFactors(int n) {
List<Integer> factors = new ArrayList<>();
for (int i = 2; i <= n / i; ++i) {
while (n % i == 0) {
factors.add(i);
n /= i ;
}
}
if (n > 1) {
factors.add(n);
}
return factors ;
}
I wrote the following program for the second problem of project Euler, for the question: "Project Euler #3: Largest prime factor".It is supposed to print out all the highest prime factors of the provided inputs.
import java.util.Scanner;
public class euler_2 {
public static boolean isPrime(int n) {
if (n % 2 == 0) return false;
for (int i = 3; i * i <= n; i += 2) {
if (n % i == 0)
return false;
}
return true;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
for (int i = 0; i < a; i++) {
int b = sc.nextInt();
for (int j = b; j >= 1; j--) {
boolean aa = isPrime(j);
if (aa == true && b % j == 0) {
b = j;
break;
}
}
System.out.println(b);
}
}
}
What changes can I make to the program to make it execute faster? What would be a better algorithm for this problem?
The problem with your approach is that for every number N, you try each number smaller or equal to N whether it is a prime and after that whether it is a divisor of N.
Obvious improvement is to check whether it is a divisor first and only then whether it is a prime. But most probably this will not help that much.
What you can do instead is just to start checking each number whether it is a divisor of a number. If it is a divisor, divide it. You continue this till sqrt(N).
I have not done anything with java in a long time, but here is Go implementation, which most probably any Java person will be able to transform to Java.
func biggestPrime(n uint64) uint64 {
p, i := uint64(1), uint64(0)
for i = 2; i < uint64(math.Sqrt(float64(n))) + uint64(1); i++ {
for n % i == 0 {
n /= i
p = i
}
}
if n > 1 {
p = n
}
return p
}
Using my algorithm it will take you O(sqrt(N)) to find the biggest prime of a number. In your case it was O(N * sqrt(N))
Attempt to factor the number into 2 factors. Repeat on the largest factor found so far until you find one that can't be factored -- that is the largest prime factor.
There are many different ways you might try to factor the numbers, but since they are only ints, then Fermat's method or even trial division (going down from sqrt(N)) will probably do. See http://mathworld.wolfram.com/FermatsFactorizationMethod.html