调用两次递归函数
2015-10-10
2012
我想要做的是计算帕斯卡三角形中坐标的值,我得到了一个带有 X 和 Y 轴 的表格,其中我的帕斯卡三角形在顶部和左侧对齐,我想做的是创建一个函数来返回特定点的值 [例如 (3,2) = 2] 这是我尝试过的:
var getCalc = function value( x, y ) {
if( y == 0 || y == x ){
return 1;
}
return value(x - 1, y - 1) + value(x - 1, y);
}
这是带有帕斯卡三角形的表格:
我们在这里得到的是一个在最后一次返回中调用两次的递归函数,执行它时我收到以下错误:
Uncaught RangeError: Maximum call stack size exceeded
此外,我想知道如何使用 ES6 做到这一点
2个回答
JavaScript 主要是 ECMAScript,您正在执行任何违反版本 6 规范的操作,但您可以 在此处进行 lint 。
- 您的 帕斯卡三角形 表看起来像是行而不是标准对角线(此答案处理对角线,但如果这是您想要的,请在最后提供一个非对角线示例)。
- 您的代码应该通过美化器运行。
- 无需制作 2 个函数(getCalc 和 value)
- 当 y == x 时,结果不应始终为 1
- 您正在对错误的框(x - 1,y - 1)求和,就像一个正方形而不是三角形(x, y - 1)
更正后的函数:
var value = function(x, y) {
if (y == 0 || x == 0) {
return 1;
}
return value(x - 1, y) + value(x, y - 1);
};
此外,如果数字非常大或数字无效,您仍然可能会收到“调用堆栈大小超出”的错误,安全包装器可能如下所示:
var safeValue = function(x, y) {
if (x > 20 || y > 20 || y < 0 || x < 0 || Math.floor(x) != x || Math.floor(y) != y ) {
return null;
}
return value(x, y);
};
如果您在任何浏览器中使用 Web 开发人员工具来设置断点,则可以跟踪每次递归以及所有变量。 您可以添加深度变量来跟踪发生了多少次递归。
输出 验证 :
(-1,0)=null
(0,0)=1
(2,3)=10
(2.5,3)=null
与大多数递归一样,您也可以将其表示为循环,并且深度限制大大减少。
var value2 = function(x, y) {
var xp;
var yp;
var theArray = {};
for (xp = 0; xp <= x; xp += 1) {
for (yp = 0; yp <= y; yp += 1) {
if (xp === 0 || yp === 0) {
if (!theArray[xp]) {
theArray[xp] = {};
}
theArray[xp][yp] = 1;
} else {
if (!theArray[xp]) {
theArray[xp] = {};
}
theArray[xp][yp] = theArray[xp - 1][yp] + theArray[xp][yp - 1];
//memory saving step
if (theArray[xp - 1][yp]) {
delete theArray[xp - 1][yp];
}
}
}
}
return theArray[x][y];
};
从时间测试中可以看出,它有很大的不同:
var a=new Date().getTime();console.log(value(13,13));console.log('time='+(new Date().getTime()-a));
10400600
time=4526
var a=new Date().getTime();console.log(value2(13,13));console.log('time='+(new Date().getTime()-a));
10400600
time=0
因此,将函数从 O(n^n) 内存移到 O(n) 后,有一个函数将使用 O(n) 时间,而不是O(n*n);
var value3 = function(x, y) {
var sum = 0;
var tmp;
var xp;
for (xp = 0; xp <= x; xp += 1) {
if (xp === 0) {
tmp = 1;
} else {
tmp = (y + xp) / xp;
}
if (sum === 0) {
sum = tmp;
} else {
sum = sum * tmp;
}
}
return sum;
};
同样,时间差异巨大;
var a=new Date().getTime();console.log(value2(500,500));console.log('time='+(new Date().getTime()-a));
2.702882409454366e+299
time=24
var a=new Date().getTime();console.log(value3(500,500));console.log('time='+(new Date().getTime()-a));
2.7028824094543663e+299
time=0
或者如果您想要非对角行:
var value4 = function(x, y) {
if (y < x) {
return null;
}
var sum = 0;
var tmp;
var xp;
for (xp = 0; xp <= x; xp += 1) {
if (xp === 0) {
tmp = 1;
} else {
tmp = (y - (xp - 1)) / xp;
}
if (sum === 0) {
sum = tmp;
} else {
sum = sum * tmp;
}
}
return sum;
};
user1133275
2015-10-10
并且
getCalc(3,2) = 3
//此函数是错误的
请查看 此实现 打印帕斯卡三角形:
getCalc(3,2)
-> getCalc(2,1) + getCalc(2,2)
->getCalc(1,0) + getCalc(1,1) + 1
->1 +1 +1= 3
构建整个三角形的代码片段:
function pascalRecursive(n, a) {
if (n < 2) return a; // We already have the top row
var prevTier = a[a.length-1];
var curTier = [1];
for (var i = 1; i < prevTier.length; i++) {
curTier[i] = prevTier[i] + prevTier[i-1];
}
curTier.push(1);
a.push(curTier);
return pascalRecursive(n-1, a);
}
var triangle = pascalRecursive(100, [[1]]);
alert(triangle[1]);
///sum
alert(triangle[1].reduce(function(pv, cv) { return pv + cv; }, 0))
Alvaro Silvino
2015-10-10