作为Haskell中合格列表推导的一个例子,Learn You a Haskell教程提供了一个列表推导的示例,它建议了一种寻找具有给定周长p
的正确三角形的一般方法,表示为元组:
λ> let rightTriangles p = [ (a,b,c) | c <- [1..(quot p 2)], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, a + b + c == p]
但随着p
变大,这种方法变得非常。
对于大型p
,是否存在通常更快但惯用的Haskell方法来完成同样的事情?
答案 0 :(得分:6)
评论指出,你真正需要的是更好的算法。
但是,让我们尝试不同的东西,看看我们可以对当前代码做出哪些优化:
let rightTrianglesCubic p = [ (a,b,c) | c <- [1..quot p 2], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, a + b + c == p]
首先,请注意我们如何循环[1..b]
的所有值,直到我们找到a + b + c == p
的值。但是唯一的值是a = p - b - c
,所以我们可以完全跳过循环,并将其转换为二次算法:
let rightTrianglesQuadraticA p = [ (a,b,c) | c <- [1..quot p 2], b <- [1..c], let a = p - b - c, a^2 + b^2 == c^2]
这种方法存在一些问题:
λ rightTrianglesCubic 120
[(30,40,50),(24,45,51),(20,48,52)]
λ rightTrianglesQuadraticA 120
[(40,30,50),(30,40,50),(45,24,51),(24,45,51),(48,20,52),(20,48,52),(0,60,60)]
我们得到了一些额外的结果!这是因为我们忽略了a <- [1..b]
所做的隐含条件,即1 <= a
和a <= b
。所以,让我们重新加入。
let rightTrianglesQuadraticB p = [ (a,b,c) | c <- [1..quot p 2], b <- [1..c], let a = p - b - c, a^2 + b^2 == c^2, 1 <= a, a <= b]
现在我们得到了正确的答案:
λ rightTrianglesQuadraticB 120
[(30,40,50),(24,45,51),(20,48,52)]
由于b
的每个值都有唯一的a
,因此条件1 <= a
和a <= b
可以在b
上表达为条件。 1 <= a
与1 <= p - b - c
或{}相同
b <= p - c - 1
。 a <= b
与p - b - c <= b
或p - c <= 2*b
或相同
div (p - c + 1) 2 <= b
。
这让我们缩小了循环b <- [1..c]
上的界限:
let rightTrianglesQuadraticC p = [ (a,b,c) | c <- [1..quot p 2], b <- [max 1 (div (p - c + 1) 2) .. min c (p - c - 1) ], let a = p - b - c, a^2 + b^2 == c^2]
我们甚至可以缩小c <- [1..quot p 2]
上的界限,注意a < b < c
a+b+c == p
c > p/3
,我们必须let rightTrianglesQuadraticD p = [ (a,b,c) | c <- [1 + quot p 3..quot p 2], b <- [max 1 (div (p - c + 1) 2) .. min c (p - c - 1) ], let a = p - b - c, a^2 + b^2 == c^2]
:
ParseQuery<ParseObject> query = ParseQuery.getQuery("GameScore");
query.whereEqualTo("playerName", "Dan Stemkoski");
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> scoreList, ParseException e) {
if (e == null) {
Log.d("score", "Retrieved " + scoreList.size() + " scores");
} else {
Log.d("score", "Error: " + e.getMessage());
}
}
});
这就是优化这个特定代码所能实现的。为了进一步提高性能,我们需要完全切换算法。