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);
}
}
}
}
Related
This question already has answers here:
How to count each digit in a range of integers?
(11 answers)
Closed last year.
I've been trying to find the most optimized way to compute the number of occurrences of each digit from 0 to 9 in a random range of numbers typed in by the user for a random personal project.
Say, the user enters 1 as the lower bound (inclusive) and 20 as the upper bound (inclusive). Output should be like this:
2 12 3 2 2 2 2 2 2 2
User can only enter positive integers.
Now, the below code runs fine for small range of numbers/ small bounds, however, as expected it takes 4 seconds+ on my laptop for large numbers/range.
I've been trying to find a way to make things quicker, I used modulus to get the digits thinking maybe string conversion is to blame, but it didn't increase speed that much. I want to reduce runtime to less than 2 seconds. There must be a way, but what? Here is my original code:
import java.util.Scanner;
public class CountDigitsRandomRange {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
String g = s.nextLine();
while (!g.equals("0 0")) {
String[] n = g.split(" ");
long x = Long.parseLong(n[0]);
long y = Long.parseLong(n[1]);
long zero = 0;
long one = 0;
long two = 0;
long three = 0;
long four = 0;
long five = 0;
long six = 0;
long seven = 0;
long eight = 0;
long nine = 0;
for (long i = x; i <= y; i++) {
String temp = String.valueOf(i);
for (int j = 0; j < temp.length(); j++) {
if (temp.charAt(j) == '0') {
zero++;
}
if (temp.charAt(j) == '1') {
one++;
}
if (temp.charAt(j) == '2') {
two++;
}
if (temp.charAt(j) == '3') {
three++;
}
if (temp.charAt(j) == '4') {
four++;
}
if (temp.charAt(j) == '5') {
five++;
}
if (temp.charAt(j) == '6') {
six++;
}
if (temp.charAt(j) == '7') {
seven++;
}
if (temp.charAt(j) == '8') {
eight++;
}
if (temp.charAt(j) == '9') {
nine++;
}
}
}
System.out.println(zero + " " + one + " " + two + " "+three + " " + four
+ " " + five + " " + six + " " + seven + " " + eight + " " + nine);
g=s.nextLine();
}
}
}
I've seen some solutions online similar to my issue but they're mostly in C/C++, I don't get the syntax.
Here is a simple implementation that uses modulus. If you want a faster code, you will need to find some smart formula that gives you the result without performing the actual computation.
import java.util.Arrays;
public class Counter
{
private static long[] counts = new long[10];
public static void count(long x, long y)
{
Arrays.fill(counts, 0);
for(long val=x; val<=y; val++)
count(val);
}
public static void count(long val)
{
while(val>0)
{
int digit = (int)(val % 10);
counts[digit]++;
val /= 10;
}
}
public static void main(String[] args)
{
count(1, 20);
System.out.println(Arrays.toString(counts));
}
}
Output:
[2, 12, 3, 2, 2, 2, 2, 2, 2, 2]
So here is an issue you might not be aware of #Sammie. In my opinion, you should NOT use the seconds provided by your runner in Java to count time when it comes to making operations more efficient. As far as I am informed, a more objective calculation is to use internal methods of Java which depend on the CPU clock to count time. This way there is less variation between different PC's (although this I don't believe is fully eliminated). Please check my references below:
Clock milis (only use this if you cannot use the solution below)
Nanoseconds
Edit: Here is another stack overflow post discussing this matter. Nanoseconds seem to be preferable.
All you need to do after that is convert into minutes, and you should now be calculating more precisely.
The code works just fine for the int data type, but 600851475143 seems to be too big of a number. How can I make it work? It just keeps running and never gives me an answer.
public class Main {
public static void main(String[] args) {
long a = 600851475143L;
boolean prime = false;
long big = 0L;
for (long i = 1L; i < a; i++){
if (a % i == 0){
for (int j = 2; j < i/(float)2; j++){
if (i % j == 0){
prime = true;
break;
}
}
if(!prime){
big = i;
}
}
}
System.out.println(big);
}
}
You need to use a long also for j.
Your variable naming is also a bit misleading: prime is true when the number is not a prime ...
Your code has a lot of problems. My first advice would be to write clean and concise code with well-named variables. Secondly, analyze the runtime complexity of your program even if it works fast for large inputs. The fact that you run an inner loop inside if(a % i == 0) condition, makes your program extremely inefficient.
Here I provide a refactored version of your code with runtime complexity and good variable names in mind:
public static void main(String[] args) {
System.out.println(largestPrimeFactorOf(600851475143L));
}
public static long largestPrimeFactorOf(long input)
{
List<Long> factors = new ArrayList<>();
// You start from 2, as 1 is not a prime number and also using 1 will cause an infinite loop
for (long i = 2L; i < input; i++) {
if (input % i == 0) {
factors.add(i);
while (input % i == 0) {
input /= i;
}
}
}
// As we always add a bigger number to the factor list, the last element is the greatest factor.
return factors.get(factors.size() - 1);
}
Denote that this program will still be slow when the input is a large prime number, e.g. 100000000019. To handle such cases efficiently, it's better to use an efficient primality test algorithm. You can search the web for that.
https://en.wikipedia.org/wiki/Primality_test
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.
I am trying to solve this question as the preparation for a programming interview:
A frog only moves forward, but it can move in steps 1 inch long or in jumps 2 inches long. A frog can cover the same distance using different combinations of steps and jumps.
Write a function that calculates the number of different combinations a frog can use to cover a given distance.
For example, a distance of 3 inches can be covered in three ways: step-step-step, step-jump, and jump-step.
I think there is a quite simple solution to this, but I just can't seem to find it. I would like to use recursion, but I can't see how. Here is what I have so far:
public class Frog {
static int combinations = 0;
static int step = 1;
static int jump = 2;
static int[] arr = {step, jump};
public static int numberOfWays(int n) {
for (int i = 0; i < arr.length; i++) {
int sum = 0;
sum += arr[i];
System.out.println("SUM outer loop: " + sum + " : " + arr[i]);
while (sum != 3) {
for (int j = 0; j < arr.length; j++) {
if (sum + arr[j] <= 3) {
sum += arr[j];
System.out.println("SUM inner loop: " + sum + " : " + arr[j]);
if (sum == 3) {
combinations++;
System.out.println("Combinations " + combinations);
}
}
}
}
}
return combinations;
}
public static void main(String[] args) {
System.out.println(numberOfWays(3));
}
}
It doesn't find all combinations, and I think the code is quite bad. Anyone have a good solution to this question?
Think you have an oracle that knows how to solve the problem for "smaller problems", you just need to feed it with smaller problems. This is the recursive method.
In your case, you solve foo(n), by splitting the possible moves the frog can do in the last step, and summing them):
foo(n) = foo(n-1) + foo(n-2)
^ ^
1 step 2 steps
In addition, you need a stop clause of foo(0) = 1, foo(1)=1 (one way to move 0 or 1 inches).
Is this recursive formula looks familiar? Can you solve it better than the naive recursive solution?
Spoiler:
Fibonacci Sequence
Here's a simple pseudo-code implementation that should work:
var results = []
function plan(previous, n){
if (n==0) {
results.push(previous)
} else if (n > 0){
plan(previous + ' step', n-1)
plan(previous + ' hop', n-2)
}
}
plan('', 5)
If you want to improve the efficiency of an algorithm like this you could look into using memoization
Here's a combinatoric way: think of n as 1 + 1 + 1 ... = n. Now bunch the 1's in pairs, gradually increasing the number of bunched 1's, summing the possibilities to arrange them.
For example, consider 5 as 1 1 1 1 1:
one bunch => (1) (1) (1) (11) => 4 choose 1 possibilities to arrange one 2 with three 1's
two bunches => (1) (11) (11) => 3 choose 2 possibilities to arrange two 2's with one 1
etc.
This seems directly related to Wikipedia's description of Fibonacci numbers' "Use in Mathematics," for example, in counting "the number of compositions of 1s and 2s that sum to a given total n" (http://en.wikipedia.org/wiki/Fibonacci_number).
This logic is working fine. (Recursion)
public static int numberOfWays(int n) {
if (n== 1) {
return 1; // step
} else if (n== 2) {
return 2; // (step + step) or jump
} else {
return numberOfWays(n- 1)
+ numberOfWays(n- 2);
}
}
The accepted answer fails performance test for larger sets. Here is a version with for loop that satisfies performance tests at testdome.
using System;
public class Frog
{
public static int NumberOfWays (int n)
{
int first = 0, second = 1;
for ( int i = 0; i<n; i++ )
{
int at = first;
first = second;
second = at + second;
}
return second;
}
public static void Main (String[] args)
{
Console.WriteLine (NumberOfWays (3));
}
}
C++ code works fine.
static int numberOfWays(int n)
{
if (n == 1) return 1;
else if (n == 2) return 2;
else
{
static std::unordered_map<int,int> m;
auto i = m.find(n);
if (i != m.end())
return i->second;
int x = numberOfWays(n - 1) + numberOfWays(n - 2);
m[n] = x;
return x;
}
}
class eulerThree {
public static void main(String[] args) {
double x = 600851475143d;
for (double z = 2; z*z <= x; z++) {
if (x%z == 0) {
System.out.println(z + "PRIME FACTOR");
}
}
}
}
and the output is:
71.0
839.0
1471.0
6857.0
59569.0
104441.0
486847.0
So, I assume 486847 is the largest prime factor of x, but project euler says otherwise. I don't see a problem in my code or my math, so I'm pretty confused. Can you see anything I can't?
Firstly, you have to use an accurate arithmetic means. Others have suggested using BigInteger. You can do this. To me, it feels a bit like cheating (this will be more important for later problems that deal with much larger integers) so the more fun way (imho) is to write the necessary arbitrary precision operations yourself.
Second, 600851475143 is small enough to be done accurate with a long, which will be much faster.
Third, your loop isn't correctly checking for prime factors. You're just checking odd numbers. This is a barebones (incomplete) solution:
long num = 600851475143L;
List<Long> factors = new ArrayList<Long>(); // or use a Set
if (num & 1 == 0) {
factors.add(2L);
}
for (long i=3; i*i<=num; i+=2) {
// first check i is prime
// if i is prime check if it is a factor of num
}
Checking if something is prime has differing levels of implementation. The most naive:
public boolean isPrime(long num) {
for (long i=2; i<=num; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
Of course that does all sorts of unnecessary checking. As you've already determined you only need to check numbers up to sqrt(n) and you can eliminate even numbers (other than 2):
public boolean isPrime(long num) {
if (num & 1 == 0) {
return false; // checks divisibility by 2
}
for (long i=3; i*i<=num; i+=2) {
if (num % i == 0) {
return false;
}
}
return true;
}
But you can do better than this as well. Another optimization is that you only need to check a number by prime numbers within that range. The prime factors of 63 are 3 and 7. If a number isn't divisible by 3 or 7 then it by definition won't be divisible by 63.
So what you want to do is build up probably a Set<Long> or prime numbers until the square is equal to or higher than your target number. Then just check this series of numbers for divisibility into the target.
double is inherently inaccurate for large values and should never be used for these type of number operations. The right class to use is BigInteger, which allows arbitrarily large integral values to be represented precisely. See this wikipedia article for a description on what floating point data types are and are not.
First, use BigInteger or long rather than double. Double isn't exact, and as you get to later problems, it won't be correct at all.
Second, what you're printing is factors, not prime factors.
This will work in your case:
for (double z = 2; z <= x; z++) {
if (x%z == 0) {
while( x%z == 0)
x = x/z
System.out.println(z + "PRIME FACTOR");
}
}
Also, Project Euler gives you sample input and output. Use that, since your code doesn't output values that match the example they give in the problem.
Two things:
Don't use double, the bigger the numbers the less precision it has. Instead you can use BigInteger to store arbitrarily large integers, or in this case a simple long will suffice.
You need to divide by the prime factor after you find it, otherwise you'll find all factors not just prime factors. Something like this:
if (x % z == 0) {
System.out.println(z + "PRIME FACTOR");
x /= z;
z -= 1; // Might be present multiple times, try it again
}
public class Prime {
public static void main(String[] args) {
double out = 0;
double m = 600851475143d;
for (double n = 3; n < m; n += 2) {
while (m % n == 0) {
out = n;
m = m / n;
}
}
System.out.println("" + ((m == 1)?out:m));
}
}
See the program. And you'll understand the algorithm. This is very easy and very fast. And return the correct answer 6857.
import java.util.Scanner;
class Primefactor
{
public static void main(String args[])
{
Scanner get=new Scanner(System.in);
System.out.println("Enter a number");
long number=get.nextLong();
int count=0;
long input=number;
for(long i=number;i>=1;number--)
{
for(long j=number;j>=1;j--)
{
if(i%j==0)
{
count++;
}
if(count==2)
{
if(input%j==0)
{
System.out.println(j);
}
}
}
}
}
}
This is to see largest primefactor of any number within the datatype limit.
public static void largestPrimeNo(long lim)
{
long newNum = lim;
long largestFact = 0;
int counter = 2;
while( counter * counter <= newNum )
{
if(newNum % counter == 0)
{
newNum = newNum / counter;
largestFact = counter;
}else{
counter++;
}
}
if(newNum > largestFact)
{
largestFact=newNum;
}
System.out.println(largestFact);
}
}
as Prime no is work on the principle that Any integer greater than 1 is either a prime number, or can be written as a unique product of prime numbers.So we can easily use above program.In this program we divide the long no,and find its prime factor
package findlaragestprimefactor;
public class FindLaragestPrimeFactor{
boolean isPrime(long number) {
for (long divider = 2; divider <= number / 2; divider++) {
if (number % divider == 0) {
return false;
}
}
return true;
}
void calculateLargestPrimeFactor() {
long largestPrimeFactor = 0;
long x = 600851475143L;
for(long factor = 3 ; factor <= x/2 ; factor = factor + 2){
if(x%factor==0 & factor>largestPrimeFactor & isPrime(factor)){
largestPrimeFactor = factor;
}
}
System.out.println(largestPrimeFactor);
}
public static void main(String[] args) {
MyProject m = new MyProject();
m.calculateLargestPrimeFactor();
}
}
long tNum=600851475143L;
ArrayList<Integer> primeNum=new ArrayList();
System.out.println(10086647/1471);
for(int i=2;i<=tNum;i++) {
if(tNum%i==0) {
primeNum.add(i);
tNum=tNum/i;
}
}
System.out.println(primeNum);