Good morning! Here’s your coding interview problem for today.

This problem was asked by Microsoft.

A number is considered perfect if its digits sum up to exactly 10.

Given a positive integer n, return the n-th perfect number.

For example, given 1, you should return 19. Given 2, you should return 28.

题目意思:所谓perfect number ,指一个正整数,如果这个数的每一位数字加起来等于10。第一个perfect number是19 (1+9=10),第二个是28(2+8=10)。要求你写个函数能够返回第n个perfect number。

solution:

方法一:暴力查找

直接从start=19开始计算,每次判断下是否为完美数字,如果是,则count++  ,然后start+1,进行下次判断。
    /**
     * 暴力查找的方式
     *
     * @param nth
     * @return
     */
    public static List<Integer> findNthMethod1List(int nth) {
        List<Integer> list = new ArrayList<>(nth);
        int start = 19;
        int count = 0;
        while (count <= nth) {
            int temp = start;
            int sum = 0;
            while (temp != 0) {
                sum = temp % 10 + sum;
                temp = temp / 10;
            }
            if (sum == 10) {
                list.add(start);
                count++;
            }
            start++;
        }
        return list;
    }

 

方法二:增加步长,提高效率

方法一中start++的方式,比较慢。我们可以每次start= start+9 ,这样会快很多。如下:
    public static int findNthMethod2(int n) {
        int count = 0;

        for (int curr = 19; ; curr += 9) {

            // Find sum of digits in current no.
            int sum = 0;
            for (int x = curr; x > 0; x = x / 10) {
                sum = sum + x % 10;
            }

            // If sum is 10, we increment count
            if (sum == 10) {
                count++;
            }

            // If count becomes n, we return current
            // number.
            if (count == n) {
                return curr;
            }
        }
    }

 

注意:
1.这里虽然每次可以+9,但是有个问题,比如假设到271, 280, 下一个完美数就并不是289。网上不少人写的算法有这个问题,认为可以直接通过n而不需要count变量来得到第n个完美数。这就是问题的关键点,我们找不到一个公式将完美数与n直接关联上,必须通过count来计数,从count=0一直累加到count= n。否则,我们只能保证算法返回的是完美数,但是这个数很可能并不是第n个原文的方法三就是个错误的算法,我在最后面的测试代码中有对比
2.步长不仅可以是9,其实也可以是10。从0开始,每次加10,此时start=10 ,start/10=1,   此时每个位数字和位1,则末尾就是10-1=9,第一个完美数就是19, start=19+10 ,  29/10=2  ,则末尾就是10-2=8 ,第二个完美数就是28。如果上一个完美数是280,则(280+10)/10=29 , 2+9>10 , 所以继续加10:290+10=300 ,300/10=30 ,则末尾就是10-3-0=7 ,这个完美数就是307 ,依次类推。这里9比10好,就是因为加9刚好让低位减少1,高位+1,再大多数情况下,+9都能直接得到完美数,不用再推算最后一位的值。
下面是完整的代码,增加了对数器来用生成测试用例,检测算法是否正确:
package testAlgorithms;

import java.util.ArrayList;
import java.util.List;

public class FindPerfectNumberTest {


    public static void main(String[] args) {

        System.out.println(isPerfect(18));
        System.out.println(isPerfect(28));
        System.out.println("checkAlgorithm:" + checkAlgorithm(10000));
    }


    /**
     * 检测算法是否正确
     *
     * @param nth
     * @return
     */
    public static boolean checkAlgorithm(int nth) {
        long startTime = System.currentTimeMillis();
//        List<Integer> myList = findNthMethod2List(nth);
//        List<Integer> myList = findNthMethod3List(nth);
        List<Integer> myList = findNthErrMethodList(nth);
        long endTime = System.currentTimeMillis();
        System.out.println(" effective method use time :" + (  endTime-startTime));
        startTime = System.currentTimeMillis();
        List<Integer> correctList = findNthMethod1List(nth);
//        List<Integer> correctList = findNthMethod3List(nth);
        endTime = System.currentTimeMillis();
        System.out.println(" bruce method use time :" + (endTime-startTime));
        for (int i = 0; i < myList.size(); i++) {
            if (!myList.get(i).equals(correctList.get(i))) {
                System.out.println("myList:      " + myList);
                System.out.println("correctList: " + correctList);
                System.out.println("wrong nth:" + (i + 1) + " ; my: " + myList.get(i) + " ;  correct : " + correctList.get(i));
                return false;
            }
        }

        return true;
    }

    /**
     * 暴力查找的方式
     *
     * @param nth
     * @return
     */
    public static int findNthMethod1(int nth) {
        int start = 19;
        int count = 0;
        while (count <= nth) {
            int temp = start;
            int sum = 0;
            while (temp != 0) {
                sum = temp % 10 + sum;
                temp = temp / 10;
            }
            if (sum == 10) {
                count++;
                return start;
            }
            start++;
        }
        return start;
    }

    /**
     * 暴力查找的方式
     *
     * @param nth
     * @return
     */
    public static List<Integer> findNthMethod1List(int nth) {
        List<Integer> list = new ArrayList<>(nth);
        int start = 19;
        int count = 0;
        while (count <= nth) {
            int temp = start;
            int sum = 0;
            while (temp != 0) {
                sum = temp % 10 + sum;
                temp = temp / 10;
            }
            if (sum == 10) {
                list.add(start);
                count++;
            }
            start++;
        }
        return list;
    }





    public static boolean isPerfect(int value) {
        int sum = 0;
        while (value != 0) {
            sum = value % 10 + sum;
            value = value / 10;
        }
        if (sum == 10) {
            return true;
        }
        return false;
    }

    /**
     * 步长为9
     * @param n
     * @return
     */
    public static int findNthMethod2(int n) {
        int count = 0;

        for (int curr = 19; ; curr += 9) {

            // Find sum of digits in current no.
            int sum = 0;
            for (int x = curr; x > 0; x = x / 10) {
                sum = sum + x % 10;
            }

            // If sum is 10, we increment count
            if (sum == 10) {
                count++;
            }

            // If count becomes n, we return current
            // number.
            if (count == n) {
                return curr;
            }
        }
    }


    public static List<Integer> findNthMethod2List(int n) {
        List<Integer> list = new ArrayList<>(n);
        int count = 0;

        for (int curr = 19; ; curr += 9) {

            // Find sum of digits in current no.
            int sum = 0;
            for (int x = curr; x > 0; x = x / 10) {
                sum = sum + x % 10;
            }

            // If sum is 10, we increment count
            if (sum == 10) {
                list.add(curr);
                count++;
            }

            // If count becomes n, we return current
            // number.
            if (count == n) {
                return list;
            }
        }
    }

    /**
     * 步长为10的
     * @param n
     * @return
     */
    public static List<Integer> findNthMethod3List(int n) {
        List<Integer> list = new ArrayList<>(n);
        int count = 0;

        for (int curr = 0; ; curr += 10) {

            // Find sum of digits in current no.
            int sum = 0;
            int temp = curr/10;
            for (int x = curr/10; x > 0; x = x / 10) {
                sum = sum + x % 10;
            }
            if(sum > 10 ||sum ==  0){
                continue;
            }else {
                int left = 10 - sum;
                list.add(temp*10+left);
                count++;
            }
            // If count becomes n, we return current
            // number.
            if (count == n) {
                return list;
            }
        }
    }


    /**
     * Error Method ,wrong algorithm
     * @param n
     * @return
     */
    public static int findNthErrMethod(int n)
    {
        int nthElement = 19 + (n - 1) * 9;
        int outliersCount = (int)Math.log10(nthElement) - 1;

        // find the nth perfect number
        nthElement += 9 * outliersCount;
        return nthElement;
    }

    /**
     * Error Method ,wrong algorithm
     * @param n
     * @return
     */
    public static List<Integer> findNthErrMethodList(int n)
    {
        List<Integer> list = new ArrayList<>(n);
        for (int i = 1; i <= n ;i++){
            list.add(findNthErrMethod(i));
        }
        return list;
    }
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.