简体   繁体   中英

How do I effectively generate Perfect digit-to-digit invariant numbers in Java?

A PDDI is a number such the the sum of all the digits raised to themselves is equal to the number itself.

For example, 3435 = (3^3) + (4^4) + (3^3) + (5^5)

The code below takes too long to check for PDDIs between one to a huge number. Is there any way to make it faster?

    System.out.print("Enter the number");
    Scanner s = new Scanner(System.in);
    int n = s.nextInt();

    int m = 0, sum = 0, k = 0;
    // We're going to try all integers between one to n.
    for(int i = 1; i<=n; i++){
       sum = 0;
       m = i;
       while(m>0){
          k = m % 10;
          sum = sum + (int)Math.pow(k, k);
          m = m/10;
       }

       if(i == sum)
          System.out.println(i);
    }

The number from 0 to 9 to the power of 2 can be precalculated and kept in a an array.

int powered [] = new int [10];
powered[0] = 0;
powered[1] = 1;
powered[2] = 4;
..
powered[9] = 81;

Then for each digit fech the powered number using the digit as an index to the powered array.

For example 234 would be powered[2] + powered[3] + powered[4]

This will save some math operations.

Also you could think of a multithreaded approach having N threads doing the calculations for different numbers in parallel.

Use cached values instead of Math.pow

Since you are using only power from 0 to 9, you could cache these values in a int[] instead of computing Math.pow(k, k) everytime. It won't improve that much but, it's a start.

int[] pows = new int[] {0, 1, 4, 27, 256, 3125, 46656, 823543, 16777216, 387420489 };
for (int i = 0; i < 10; ++i) {
    pows[i] = (int) Math.pow(i, i);
}

System.out.print("Enter the number");
Scanner s = new Scanner(System.in);
int n = s.nextInt();

int m = 0, sum = 0, k = 0;
// We're going to try all integers between one to n.
for(int i = 1, i<=n, i++){
   sum = 0;
   m = i;
   while(m>0){
      k = m % 10;
      sum = sum + pows[k]; // use cached values here
      m = m/10;
   }

   if(i == sum)
      System.out.println(i);
}

Skip useless values

Based on logic you may skip some iterations. Lets take the number 281 as an example, which gives 4 + 16777216 + 1 = 16777251 , the result is above 281, so theres no changes that 282, 283, 284, ... 289 gives a number equals to 281. In such cases you may want to skip these useless iterations by manually incrementing i .

int[] pows = new int [10];
for (int i = 0; i < 10; ++i) {
    pows[i] = (int) Math.pow(i, i);
}

System.out.print("Enter the number");
Scanner s = new Scanner(System.in);
int n = s.nextInt();

int m = 0, sum = 0, k = 0, lastNumberDigit;
// We're going to try all integers between one to n.
for(int i = 1, i<=n, i++){
   sum = 0;
   m = i;
   while(m>0){
      lastNumberDigit = m; // on the last iteration, we'll get the last digit
      k = m % 10;
      sum = sum + pows[k]; // use cached values here
      m = m/10;
   }

   if(i == sum) {
      System.out.println(i);
   } else if (sum > i) {
      i += (10 - lastNumberDigit - 1); // jump to the next decade (-1 because the for will apply i++ on it)
   }
}

I used this logic on decade, but you may want to extend it to hundreds or even more, but it will be much more tricky.

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