我解决了以下练习,但我不是解决方案的粉丝:
使用递归编写函数isPerfectSquare,判断是否有 Int是一个完美的广场 isPerfectSquare 1 - >应该返回True isPerfectSquare 3 - >应该返回False
<platform name="ios">
<resource-file src="path/to/your.xib" />
</platform>
部分适用于num+1
的情况,其中一个部分我不喜欢一点,这是我的解决方案:
isPerfectSquare 0 and isPerfectSquare 1
这个问题有什么更优雅的解决方案?当然,我们不能使用sqrt,也不能使用浮点运算。
答案 0 :(得分:5)
@luqui你的意思是这样吗?
pow n = n*n
perfectSquare pRoot pSquare | pow(pRoot) == pSquare = True
| pow(pRoot)>pSquare = perfectSquare (pRoot-1) pSquare
| otherwise = False
--
isPerfectSquare number = perfectSquare number number
我无法相信我没有看到它xD非常感谢!我一定很累了
答案 1 :(得分:3)
您可以执行某种&#34;二分搜索&#34;在一些隐含的正方形列表上。然而,当然存在一个问题,那就是我们首先需要一个上限。我们可以使用数字本身作为上限,因为对于所有整数正方形,正方形大于我们平方的值。
所以它看起来像:
isPerfectSquare n = search 0 n
where search i k | i > k = False
| j2 > n = search i (j-1)
| j2 < n = search (j+1) k
| otherwise = True
where j = div (i+k) 2
j2 = j * j
为了验证数字 n 是一个完美的正方形,我们因此有一个在 O(log n)中运行的算法,以防整数运算在常量中完成时间(例如,如果位数是固定的)。
答案 2 :(得分:1)
Wikipedia suggests using Newton's method.这就是看起来的样子。我们将从一些样板开始。 ensure
是我经常使用的一个小组合子。它写得非常通用,但我已经加入了一个简短的评论,对于我们计划如何使用它应该是非常明确的。
import Control.Applicative
import Control.Monad
ensure :: Alternative f => (a -> Bool) -> a -> f a
ensure p x = x <$ guard (p x)
-- ensure p x | p x = Just x
-- | otherwise = Nothing
这是维基百科给出的在牛顿方法中迈出一步的公式的实现。 x
是我们目前关于平方根的猜测,n
是我们取平方根的数字。
stepApprox :: Integer -> Integer -> Integer
stepApprox x n = (x + n `div` x) `div` 2
现在我们可以递归调用这个步进函数,直到得到平方根的底部。由于我们使用整数除法,因此正确的终止条件是观察近似的下一步与当前步骤相等或更大。这是唯一的递归函数。
iterateStepApprox :: Integer -> Integer -> Integer
iterateStepApprox x n = case x' - x of
0 -> x
1 -> x
_ -> iterateStepApprox x' n
where x' = stepApprox x n
要将整个开发包装在一个漂亮的API中,要检查数字是否为正方形,我们可以检查其平方根的平面是否正方形。我们还需要选择一个起始近似值,但我们不必非常聪明 - 牛顿方法很快收敛于平方根。我们将选择一半的数字(四舍五入)作为近似值。为了避免被零和其他废话分开,我们将使零和负数特殊情况。
isqrt :: Integer -> Maybe Integer
isqrt n | n < 0 = Nothing
isqrt 0 = Just 0
isqrt n = ensure (\x -> x*x == n) (iterateStepApprox ((n+1)`div`2) n)
现在我们完成了!即使是大数字也很快:
> :set +s
> isqrt (10^10000) == Just (10^5000)
True
(0.58 secs, 182,610,408 bytes)
你的花费时间比宇宙离开计算的时间要长。它在我的测试中也比二进制搜索算法快一点。 (当然,not hand-rolling it yourself仍然快几个数量级,可能部分是因为它使用better, but more complicated, algorithm based on Karatsuba multiplication。)
答案 3 :(得分:0)
如果函数是递归的,那么它是原始递归的,因为它是所有递归函数的90%。因为这些fold
是快速有效的。考虑到程序员的时间,保持简单和正确是很重要的。
现在,也就是说,cinsider sqrt
等函数的文本模式可能会很有成效。 sqrt
返回一个浮点数。如果一个数字是一个完美的正方形,则两个字符是&#34; .0&#34;在末尾。但是,在任何尾数的开头都可能出现这种模式。如果一个字符串进入,反过来,那么&#34; 0。&#34;在列表的顶部。
此函数接受一个数字并返回一个Bool
fps n = (take 2.reverse.show $ (n / (sqrt n))) == "0."
fps 10000.00001
假
fps 10000
真