程序员的算法趣题:Q18 水果酥饼日(Java版)

题目要求

题目链接(力扣网):https://leetcode-cn.com/leetbook/read/interesting-algorithm-puzzles-for-programmers/97r135/

1.一个蛋糕切成N块,每个蛋糕上的草莓个数为1~N,且不重复

2.相邻两块蛋糕上的草莓数之和,是平方数(1,4,9,16,...)

求:满足上述要求的最小N

思路

1.让N从小往大遍历,找出第一个符合要求的就是最小值

2.集合SList用于保存平方数,如果相邻蛋糕草莓数之和存在于集合SList,则符合要求

3.集合NList用于保存1~N这N个数字,每选择一个数字就从集合中删除一个数字,NList集合删空时表示一种尝试已到尽头

4.每一步只需要知道上一步选择的数字、还有哪些数字可选、符合要求的平方数集合——递归

代码

public static void main(String[] args) {
    List nList = new LinkedList(); // 可用数字集合
    List sList = new ArrayList(); // 平方数集合

    for(int n = 1, m = 1; n < 500 ; n ++){
        nList.add(n); // 可用数字1~n
        if(m * m <= 2 * n - 1){ // 相邻蛋糕草莓数最大值:n + (n-1) == 2*n-1
            sList.add(m * m); // 平方数(没必要无限大,够用即可)
            m ++;
        }
        System.out.println(sList);

        nList.remove(new Integer(1)); // 直接填数字,会被当作下标

        if(cut(1,nList,sList)){ // 因为是个圆,所以从几开始都行。但一开始只有1块,所以此处从1开始。自定义方法cut
            System.out.println("\nmin N = "+n);
            break;
        }

    }
}
/**
 * 切蛋糕
 * @param pre   上一步选择的数字
 * @param nList 剩余可选数字(1~N)
 * @param sList 平方数集合
 */
public static boolean cut(int pre, List nList, List sList){
    if(nList == null || sList == null) return false; // 入参检查
    // 递归出口
    if(nList.size() == 0){ // 决定了该条支路的最终成败,上层的递归的返回值都只是传递这个最终结果。如果这里成功了,则该条支路全都return true
        if(sList.contains(pre + 1)){ // 因为是个圆,所以第一块从谁开始算都可以。假设从1开始。最后一块pre是否能和最开始的1拼成平方数。能拼成则成功
            System.out.print(pre+",");
            return true;
        }
        return false;
    }

    // 递归调用
    for(int i = 0; i < nList.size(); i ++){ // 剩余可用数字,逐一尝试
        int num = nList.get(i); // 本次选的数字
        if(sList.contains(num + pre)){ // 能和上一块蛋糕的草莓数构成平方数
            nList.remove(i); // 修改剩余的可用数字
            if(cut(num,nList,sList)){
                System.out.print(pre+",");
                return true;
            }else{
                nList.add(i,num); // 恢复可用数字
            }
        }
    }
    return false; // 已经尝试了当前情况的所有后续可能
}

结果

15,10,26,23,2,14,22,27,9,16,20,29,7,18,31,5,11,25,24,12,13,3,6,30,19,17,32,4,21,28,8,1,(倒着输出的)
min N = 32

你可能感兴趣的:(力扣,算法,java)