如何提高计算树中特定叶子数的速度

时间:2017-03-17 19:24:15

标签: java algorithm tree graph-theory

我有编程任务,我无法解决给定的约束。

条件:

你有 N 数量的砖块。

使用以下约束计算您可以使用这些砖建造多少楼梯:

  1. 每个楼梯应使用所有给定的砖块建造。
  2. 不允许两个高度相同的步骤。
  3. 楼梯应该至少有两个步骤。
  4. 将提供最大砖数为250。
  5. 示例:

    鉴于3块砖,你可以建造1个楼梯:

    step 1 - height 1
    step 2 - height 2
    

    鉴于4块砖,你也可以建造1个楼梯:

    step 1 - height 1
    step 2 - height 3
    

    鉴于5块砖,你可以建造2个楼梯:

    step 1 - height 2            step 1 - height 1
    step 2 - height 3            step 2 - height 4
    

    解决方案应该像下面这样实现(我正在使用Java):

    class Solution {
      public static int count(int numberOfBricks) {
        // code
      }
    }
    

    自动平地机有几个技术限制,例如。不允许使用线程,许多Java类都是有限的等等。

    我尝试使用树结构解决问题,其中每个节点保存有关剩余砖块数和当前步高的信息,每条边代表具有允许高度的步骤的构建。

    例如,以下结构代表阶梯高度的楼梯(1,2,4)(1,6)(2,5)(3,4)

    tree structure

    我尝试了几种方法:

    1. 建筑楼梯自下而上(从最低阶段到最高阶段)和自上而下(从最高阶段到最低阶段)
    2. 使用深度优先和广度优先搜索。
    3. 使用递归或迭代。
    4. 因此,我有几个通过单元测试的工作解决方案(正确解决所有样本问题)。不幸的是,我无法获得最高分,因为自动评分员告诉我,我的解决方案落后于允许的时间限制,因此存在一些更优化的方法。 我想关键是通过计算当前节点基础上可能的楼梯数来限制遍历分支的遍历。不幸的是,我对以下改进知之甚少,并会感谢任何帮助。 这是我的解决方案之一:

      import org.testng.Assert;
      
      public class Task0302 {
      
      static int numberOfStairCases = 0;
      
      public static int answer(int n) {   
        numberOfStairCases = 0;
        run(n, n - 1);
        return numberOfStairCases;
      }
      
      static void run(final int hasBricks, final int maximalAllowedHeight) {
        if (hasBricks > bricksAllowed(maximalAllowedHeight))
          return;
        if (hasBricks == bricksAllowed(maximalAllowedHeight)) {
          numberOfStairCases++;
          return;
      }
      
      int currentStepHeight = Math.min(hasBricks, maximalAllowedHeight);
      final int minHeight = minPossibleHeight(hasBricks);
       do {    
         run(hasBricks - currentStepHeight, currentStepHeight - 1);
         currentStepHeight--;
       } while (currentStepHeight >= minHeight);
      }
      
      static int minPossibleHeight(int havingBricks) {
        return (int) ((Math.sqrt(8 * havingBricks + 1) - 1) / 2);
      }
      
      static int bricksAllowed(int currentHeight) {
        return (currentHeight + 1) * currentHeight / 2;
      }
      
      public static void main(String[] args) {
       Assert.assertEquals(answer(3), 1);
       Assert.assertEquals(answer(4), 1);
       Assert.assertEquals(answer(5), 2);
       Assert.assertEquals(answer(200), 487067745);
       System.out.println("Passed");
       }
      }
      

      抱歉,这很混乱,因为我主要是在晚上和整天工作。 python 2也可以使用,但我不熟练。

1 个答案:

答案 0 :(得分:1)

你的问题等同于计算用唯一正整数求和N的方法的数量,忽略顺序。这里有一个参考:http://mathworld.wolfram.com/PartitionFunctionQ.html

使用上述链接中的生成函数的一个O(n ^ 2)算法是计算多项式乘积:乘积((1 + x ^ k)为k = 1..N),然后查看系数of x ^ N。

这听起来很难,但它的代码相对简单(这里是伪代码):

A = [1, 0, 0, ..., 0] -- an array of size N+1
for k = 1 to N
    for i = N to k step -1
        A[i] += A[i - k]
return A[N]

您可以将其视为动态编程解决方案。在k个循环的n个步骤之后,每个A [i]将使用整数1到n存储不同的求和方式的数量。或者等效地,在k循环的n个步骤之后,可以考虑数组A来表示多项式A [0] + A [1] x + A [2] x ^ 2 + ... + A [N] x ^ N,它将等于乘积(对于k = 1..n,1 + x ^ k)。

(实际上,这个解决方案包括一个大小为N的“阶梯” - 所以你必须减去1才能得到除特殊情况外的结果。)