美文网首页
求平方根或近似平方根

求平方根或近似平方根

作者: 落叶刺客 | 来源:发表于2017-08-15 01:28 被阅读50次
问题:给定一个正整数,如果它有正整数平方根,则求出它的平方根;如果它没有正整数平方根,则求出最接近的正整数平方根。不能使用sqrt(_: )函数。

  比如说,5、6、7、8都是没有正整数平方根的,但是最接近它的正整数平方根是2,而9的正整数平方根是3。现在要求写一个函数,能够计算出给定正整数的正整数平方根,或者最接近它的正整数平方根。

  这个问题的解决方案有好几种,我们先来给一个性能比较差,并且有bug的解决方案:

// 性能不好,并且有bug
func challenge(input: Int) -> Int {
    for i in 0 ... input / 2 {
        if i * i > input {
            return i - 1
        }
    }
    return 0
}

challenge(input: 15)  // 答案3

  上面这段代码比较智障,因为它只能计算[6, +∞)之间的数据,而在计算[1, 5]之间的数据时,会有问题。并且,需要计算的数据越大,程序的性能就越差。所以,这个肯定不是最终的解决方案。

  一个比较好的解决方案是使用二分查找法(Binary Search),既能完美解决bug,又极大的提高了计算性能。二分查找的思想是:先确定一个最低点x(往往从0开始),再确定一个最高点y(一般从N / 2 + 1开始),当x < y时,找到x和y的中间值z,然后用中间值z去和结果做对比,如果刚好就是z,则直接返回中间值z;如果结果还是比z大,说明我们找到的值z小了,还需要继续往更大的值上去查找,此时应该将中间值z赋值给最低点x,然后继续寻找x和y的中间值;如果结果比z小,说明我们找到的值z太大了,需要继续往更小的值上去查找,此时应该将中间值z赋值给最高点y,然后继续寻找x和y的中间值...一次类推,直至找到合适的中间值z,然后再将其返回。用代码表示为:

func challenge1(input: Int) -> Int {
    
    // 如果输入的数据恰好是1,则直接返回结果1
    guard input != 1 else { return 1 }
    
    // 指定最高点和最低点
    var lowerBound = 0
    var upperBound = 1 + input / 2
    
    // 当最低点加1小于最高点时,进入循环体
    while lowerBound + 1 < upperBound {
        
        // 确定中间点
        let middle = lowerBound + ((upperBound - lowerBound) / 2)
        
        // 对中间点进行平方操作
        let middleSquared = middle * middle
        
        // 对middleSquared和输入数据进行对比
        if middleSquared == input {
            
            // 如果middleSquared恰好和input相等,则说明middle符合题目要求,直接将其返回
            return middle
            
        } else if middleSquared < input {
            
            // 如果middleSquared比input还小,则说明middle太小了
            // 还要继续往更大的值上去查找,将middle设置为最低点,并继续下一次循环
            lowerBound = middle
            
        } else {
            
            // 如果middleSquared比input还大,则说明middle太大了
            // 还需要继续往更小的值上去查找,将middle设置为最高点,并继续下一次循环
            upperBound = middle
            
        }
    }
    
    // 返回lowerBound的值
    return lowerBound
}

challenge1(input: 5)  // 结果为2

  还有一个抖机灵的做法,题目说了不能使用sqrt(_: )函数,但是没有说不能使用pow(_: , _: )函数呀,所以我们可以利用幂函数来达到开方的目的:

// 性能又好又简洁
func challenge3(input: Int) -> Int {
    
    // 使用幂函数来实现开方的目的
    return Int(floor(pow(Double(input), 0.5)))
}

  有时候合理的利用系统自带的函数,可以极大的减少我们的开发工作。顺便提一下几个常用的数学函数:

func sqrt(_: Double) -> Double 平方根函数
func pow(_: Double, _: Double) -> Double 幂函数
func floor(_: Double) -> Double 向下取整函数
func ceil(_: Double) -> Double 向上取整函数

相关文章

网友评论

      本文标题:求平方根或近似平方根

      本文链接:https://www.haomeiwen.com/subject/dreerxtx.html