打表技巧

153 阅读2分钟

我们都知道如果一个题目输入条件是一个参数,输出也是一个参数时,大部分情况可以使用打表技巧来观察数据,从而优化代码。 题目: 小虎去买苹果,商店只提供两种类型的塑料袋,每种类型都有任意数量

1.能装下6个苹果的袋子

2.能装下8个苹果的袋子

小虎可以自由使用两种袋子来装苹果,但是小虎有强迫症,他要求自己使用的袋子数量必须最少,且使用的每个袋子必须装满。

给定一个正整数N,返回至少使用多少袋子。如果N没法使得每个袋子装满,返回-1。

代码:

/**
     * 返回需要最小的袋子
     * @param n 苹果数
     * @return 袋子数
     */
    private static int getMinBag(int n){
        int max8 = n/8;
        int total = -1;
        for(int i=max8;i>=0;i--){
            int rest = n - i * 8;

            if(rest >= 24){
                break;
            }

            if(rest % 6 == 0){
                total = i + rest / 6;
                break;
            }
        }

        return total;
    }


    /**
     * 打表发现规律写出o(1)的方法
     * @param n
     * @return
     */
    private static int getMinBag1(int n){
        if((n & 1) != 0) //奇数返回-1
            return -1;

        if(n < 18){
            if(n == 0)
                return 0;
            if(n == 2 || n == 4 || n == 10)
                return -1;
            if(n == 6 || n == 8 )
                return 1;
            if(n==12 || n == 14 || n == 16)
                return 2;
        }
        return (n - 18) /8 +3;
    }



    public static void main(String[] args) {
        for (int i = 0; i <= 100; i++) {
            System.out.println(i+"= " + getMinBag(i));
        }
    }

题目2:

给定一个正整数N,表示有N份青草统一堆放在仓库里。

有一只牛和一只羊,牛先吃,羊后吃,它两轮流吃草。

不管是牛还是羊,每一轮能吃的草量必须是:

1,4,16,64...(4的某次方)

谁先把草吃完,谁获胜。

假设牛和羊都绝顶聪明,都想赢,都会做出理性的决定。

根据唯一的参数N,返回谁会赢。

/**
     * 返回赢家
     * @param n n份草
     * @return 赢家
     */
    private static String winner(int n){
        if(n == 0){
            //先手无草可以吃,后手赢
            return "后手";
        }
        if(n == 1 || n == 3 || n == 4){
            return  "先手";
        }
        if(n == 2){
            return "后手";
        }

        int base = 1; //先手准备吃几份草
        while(base <= n){
            if(winner(n-base).equals("后手")){
                return "先手";
            }
//            if(base > n/4) break;//防止base*4大于int最大值
            base *= 4;
        }
        return "后手";
    }

    /**
     * 打表发现规律,后先后先先,时间复杂度0(1)
     * @param n
     * @return
     */
    private static String winner1(int n){
        if(n % 5 == 0 ||  n % 5 == 2)
            return "后手";
        return "先手";
    }
    

    public static void main(String[] args) {
        for (int i = 0; i <= 100; i++) {
            System.out.println(i+"= " + winner1(i));
        }
    }

题目3: 定义一种数:可以表示成若干(数量>1)连续正数和的数。

比如:

5 = 2+3,5就是这样的数

12 = 3+4+5 ,12就是这样的数

给定一个参数N,返回是不是可以表示成若干连续正数和的数。 代码:

private static boolean isValid(int n){
    for (int i = 1; i < n; i++) {
        int sum = 0;
        for(int j = i;j<n;j++){
            sum += j;
            if(sum == n){
                return true;
            }
        }
    }
    return false;
}


//打表观察发现 2,4,8,16,32都是false
private static boolean isValid1(int n){
    /*if(n == 0){
        return false;
    }
    for(int i=0;i<n;i++){
        if(Math.pow(2,i) == n){
            return false;
        }
        if(Math.pow(2,i) > n){
            return true;
        }
    }
    return true;*/

    if(n < 3){
        return false;
    }
    return (n & (n-1)) != 0;
}



public static void main(String[] args) {
    for (int i = 0; i <= 100; i++) {
        System.out.println(i+"= " + isValid1(i));
    }
}