我在一次采访中遇到了这个问题而无法理解。我相信它有一个动态的编程解决方案,但它让我望而却步。
给定多个砖块,输出可能的2d金字塔总数,其中金字塔被定义为任何结构,其中一排砖块的砖块严重少于其下方的砖块。你不必使用所有砖块。
砖块只是一个正方形,连续砖块的数量是唯一重要的信息。
真的坚持这个,我认为很容易解决每个问题1 ... n迭代和总结。但是提出金字塔的数量正好可以让我回避。
示例,n = 6
X
XX
X
XX XXX
X
XXX XXXX
XX X
XXX XXXX XXXXX
X
XX XX X
XXX XXXX XXXXX XXXXXX
所以答案是来自6块砖的13个可能的金字塔。
修改
我很肯定这是一个动态编程问题,因为(一旦你确定了第一行)有意义只需查看你剩余砖块的记忆数组中的索引,看看有多少金字塔适合于顶部。
考虑底部行的宽度至少为n / 2也是有道理的,因为我们不能在底部行上面有更多砖块除了,这是我失去它和我的思想的地方在某些(很少的情况下),你可以分崩离析N = 10
X
XX
XXX
XXXX
现在底行有4个,但最左边有6个
但是当n = 11时,我们不能有一个低于n / 2砖的底行。还有另一种奇怪的不一致性,就像n = 4那样我们不能有一排n / 2 = 2砖。
答案 0 :(得分:4)
让我们选择一个合适的定义:
f(n, m) = # pyramids out of n bricks with base of size < m
您现在正在寻找的答案是(假设N
是您输入的砖块数量):
f(N, N+1) - 1
让我们打破这一点:
N
显而易见:那就是你的砖块数量。N
块(因为这就是您所拥有的所有块),因此N+1
是一个足够的下限。- 1
就在那里,因为从技术上讲,空金字塔也是一个金字塔(因此会被计算在内),但你可以从解决方案中排除它。基本案例很简单:
f(n, 0) = 1 for any n >= 0
f(0, m) = 1 for any m >= 0
在这两种情况下,这都是我们在这里计算的空金字塔。
现在,我们所需要的只是一般案例的递归公式。
我们假设我们获得了n
和m
,并选择在底层使用i
砖块。我们可以在这一层上放置什么?一个较小的金字塔,我们留下了n - i
块砖,其底部的大小为< i
。这正是f(n - i, i)
。
i
的范围是多少?我们可以选择一个空行i >= 0
。显然,i <= n
因为我们只有n
砖块。但是,i <= m - 1
,根据m
的定义。
这会导致递归表达式:
f(n, m) = sum f(n - i, i) for 0 <= i <= min(n, m - 1)
你可以递归地计算f
,但是使用动态编程当然会更快。存储结果矩阵很简单,所以我把它留给你。
回到最初的声明f(N, N+1)-1
是您正在寻找的答案,只要它是m
,为> N
选择哪个值并不重要。根据递归公式,可以很容易地显示每个f(N, N + 1) = f(N, N + k)
k >= 1
:
f(N, N + k) = sum f(N - i, i) for 0 <= i <= min(N, N + k - 1)
= sum f(N - i, i) for 0 <= i <= N
= sum f(N - i, i) for 0 <= i <= min(N, N + 1 - 1)
答案 1 :(得分:3)
您可以通过多少种方式构建宽度 n 的金字塔?通过将任何宽度 n-1 或更小的金字塔放置在 n 砖层的顶部。因此,如果 p(n)是宽度 n 的金字塔数,那么 p(n)= sum [m = 1到n-1](p (m)* c(n,m)),其中 c(n,m)是你可以放置一层宽度 m 的方式的数量在一层宽度 n 之上(我相信你可以自己解决这个问题)。
然而,这并不限制砖的数量。通常,在DP中,必须将任何资源限制建模为单独的维度。所以你的问题现在是 p(n,b):&#34;你可以用 b 构建宽度 n 的金字塔数量>砖&#34;?在递归公式中,对于在当前建筑物上方构建较小金字塔的每种可能方式,您需要参考正确数量的剩余砖块。我把它作为一个挑战,让你找出递归公式;如果您需要任何提示,请告诉我。
答案 2 :(得分:2)
你可以将你的递归看作:在最后一行使用<!DOCTYPE html>
<html>
<head>
<script src="bower_components/angular/angular.js"></script>
<script src="app/app.js"></script>
</head>
<body ng-app="myApp" ng-controller="myController">
<ul ng-repeat="x in names">
<li>
{{ x }}
</li>
</ul>
</body>
</html>
砖的地方留下了x
砖块,你可以建造多少个金字塔。现在,您可以从上到下行或从下到上填充行。我会解释前一种情况
这里递归可能看起来像这样(n
是剩下的砖数,left
是最后一行使用的砖数)
last
因为当你在当前行上使用f(left,last)=sum (1+f(left-i,i)) for i in range [last+1,left] inclusive.
砖块时,你将剩下i
块砖,而left-i
将是此行上使用的砖块数。
代码:
i
我会留给您实施int calc(int left, int last) {
int total=0;
if(left<=0) return 0; // terminal case, no pyramid with no brick
for(int i=last+1; i<=left; i++) {
total+=1+calc(left-i,i);
}
return total;
}
或memoized
版本。另外,您可能希望从底行开始并填充金字塔中的上行。
答案 3 :(得分:2)
由于要求我们计算任何小于或等于it's id is 1 again
的基数的金字塔,我们可以依次考虑每个基数(1个元素的金字塔,2个元素,3 ......等)并将它们相加起来。但是我们可以用多少种不同的方式组成n
元素的金字塔?与k
的不同分区数相同的数字(例如,对于k
,我们可以有k = 6
)。 Wikipedia中的OEIS和Pentagonal number Theorem处的序列描述了不同分区计数的生成函数/重复。
重复,基于JSFiddle example:
(6), (1,5), (2,4), and (1,2,3)
由于维基百科中描述的重复性要求计算所有前面的q(k) = ak + q(k − 1) + q(k − 2) − q(k − 5) − q(k − 7) + q(k − 12) + q(k − 15) − q(k − 22)...
where ak is (−1)^(abs(m)) if k = 3*m^2 − m for some integer m and is 0 otherwise.
(The subtracted coefficients are generalized pentagonal numbers.)
以获得更大的q(n)
,我们可以简单地对结果进行求和以获得我们的结果。
JavaScript代码:
q(n)