简体   繁体   中英

How can I make this code more efficient? Java algorithm

I am attempting the challenge below. https://www.hackerrank.com/contests/projecteuler/challenges/euler145/submissions/code/25262675

Basically, the code needs to reverse a number of varying length from around 1-19 digits, add these numbers together and then check if the result is entirely made up of odd numbers, leading 0's are not allowed (eg 100 should be excluded).

The code I have refined can calculate these numbers, but on the site there is a timeout and I feel that it is not good enough performance-wise.

I have tried using regex, but could not get it to sort properly and it was effecting the result. Any guidance as the best way to write this so that it runs as fast as possible would be very helpful, be it if it needs to use regex or anything else.

public static void main(String[] args) {

    Scanner scan = new Scanner(System.in);
    long t = scan.nextInt(); //Number of numbers to test
    for (int i = 1; i <= t; i++){
        long n = scan.nextLong();
        calc(n); //begins calculation
    }
}

public static void calc(long n)
{
    long reversible = 0; //Counter
    for (long i = 1; i < n; i++)
    {
        if (i%10 != 0) //Makes sure number does not end with a zero
        {
            long reverse = 0;
            long j = i;
            long checkOdd;
            //Reverse the number
            while( j != 0 )
            {
                reverse = reverse * 10;
                reverse = reverse + j%10;
                j = j/10; //
            }
            long result = i + reverse; //Add current number and reverse
            while (result != 0)
            {
                //Check and remove numbers to see if odd or not
                checkOdd = result%10;
                if (checkOdd%2 == 0){ //Even detected, move to next number
                    result = 0;                        
                } 
                result = result/10; //Move to next digit
                //Counts and ensures we do not count the same number multiple times
                if (checkOdd%2 == 1 && result == 0) 
                {
                    reversible = reversible + 1;
                }
            }

            /** REGEX TEST CODE -- fails when result is 5 digits long after testing */
            /** if(Pattern.matches("\\d[^02468]", Long.toString(result)))
            {
                System.out.println(result);
                reversible = reversible + 1;
            }*/


        }
    }
    System.out.println(reversible);
}

This won't completely solve your problem, but will hopefully get you started on a way to think about this problem.

Since this is about counting the cardinality of a set, we should think about how to construct elements of that set, rather than how to check if an element is in that set.

To begin, try thinking about ways to construct numbers of a specific length.

We'll start with one digit numbers. We'll represent these as a . If we take a and reverse it, we get a . When this is doubled, we get 2a , this is always even, and thus always ends in an even digit and therefore there are none.

Next, 1 digit numbers. Represents as ab where a and b are digits. the reverse is ba , the rightmost position (I'll number from here, starting at 0 , for future references) of the sum is (a+b)%10 , so the final digit of this is only odd when exactly one of and b is odd. Additionally, a+b has a carry of 1 or 0 , we'll call this z . This is important for the next part. Position 1 in the sum is (a+b+z)%10 . Having already determined that a+b must be odd, z must now be 0 to keep this odd. So a+b < 10 . Now you just need the number of combinations of and b for which this works. Note that neither can be 0, because they are at the ends of the number.

 a | b 
 1 | 2,4,6,8
 2 | 1,3,5,7
  ... 

Of course, we really just need to be able to count these. So for a=1 we just need to know b is even and b<9 so there are 4 possibilities. For a=2 , b is odd and b<8 , so there are 4 options.

You should be able to reproduce this idea for 3 digit numbers, and hopefully in that the savings from counting the number of possibilities, without generating or verifying any of them should become more apparent.

Edit: as an aside, without the working to get there for the three digit number abc , I came to the conclusion that:

a+c is odd
a+c>=10
b<=4

Any combination meeting those rules should work. This should give 20 combinations of a,c , with 5 independent values for b thus 20 * 5 = 100 total for 3 digit numbers. Hopefully either I am wrong, or you come to the same conclusion when you try.

As you extend further than that, you should notice some patterns that allow you to generalise to any length (I think there might be some distinctions between how odd length and even length work that are important).

Actually providing a solution for you wouldn't be productive (and I'm sure they already exist somewhere), but hopefully this can shift your perception of how to go about solving the problem enough that you can solve it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM