• Sqrt(x)——二分法,防越界


    Implement int sqrt(int x).

    Compute and return the square root of x.

    转自:http://blog.csdn.net/doc_sgl/article/details/12404971

    实际面试遇到的题目可能不是对一个整数开方,而是对一个实数。方法和整数其实是一致的,只是结束条件换成左界和右界的差的绝对值小于某一个epsilon(极小值)即可。在C++中我们需要通过两个数的绝对值差小于某个极小值来判断两个double的相等性。实际上两个double因为精度问题往往是不可能每一位完全相等的。

    1. 二分法:

    这道题一看到函数的定义int sqrt(int x)都是int就高兴了,直接二分吧。但是要注意,即使用long long都TM越界,还要用unsigned long long。最后返回值还要再检查一下。

    int sqrt(int x) {  
            // Start typing your C/C++ solution below  
            // DO NOT write int main() function  
            unsigned long long begin = 0;  
            unsigned long long end = (x+1)/2;  
            unsigned long long mid;  
            unsigned long long tmp;  
            while(begin < end)  
            {  
                mid = begin + (end-begin)/2;  
                tmp = mid*mid;  
                if(tmp==x)return mid;  
                else if(tmp<x) begin = mid+1;  
                else end = mid-1;  
            }  
            tmp = end*end;  
            if(tmp > x)  
                return end-1;  
            else  
                return end;  
        }  

    2. 牛顿迭代法


       为了方便理解,就先以本题为例:

       计算x2 = n的解,令f(x)=x2-n,相当于求解f(x)=0的解,如左图所示。

       首先取x0,如果x0不是解,做一个经过(x0,f(x0))这个点的切线,与x轴的交点为x1

       同样的道理,如果x1不是解,做一个经过(x1,f(x1))这个点的切线,与x轴的交点为x2

       以此类推。

       以这样的方式得到的xi会无限趋近于f(x)=0的解。

       判断xi是否是f(x)=0的解有两种方法:

       一是直接计算f(xi)的值判断是否为0,二是判断前后两个解xi和xi-1是否无限接近。

    经过(xi, f(xi))这个点的切线方程为f(x) = f(xi) + f’(xi)(x - xi),其中f'(x)为f(x)的导数,本题中为2x。令切线方程等于0,即可求出xi+1=xi - f(xi) / f'(xi)。

    继续化简,xi+1=xi - (xi- n) / (2xi) = xi - xi / 2 + n / (2xi) = xi / 2 + n / 2xi = (xi + n/xi) / 2。

    有了迭代公式xi+1= (xi + n/xi) / 2,程序就好写了。关于牛顿迭代法,可以参考wikipedia以及百度百科

    class Solution {
    public:
        int mySqrt(int x) {
            if (x ==0)  
                return 0;  
            double pre;  
            double cur = 1;  
            do  
            {  
                pre = cur;  
                cur = x / (2 * pre) + pre / 2.0;  
            } while (abs(cur - pre) > 0.00001);  
            return int(cur);  
            
        }
    };
    float InvSqrt(float x)  
    {  
        float xhalf = 0.5f*x;  
        int i = *(int*)&x; // get bits for floating VALUE  
        i = 0x5f375a86- (i>>1); // gives initial guess y0  
        x = *(float*)&i; // convert bits BACK to float  
        x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy  
        return x;  
    }  
  • 相关阅读:
    团队开发冲刺日(十三)
    第十周总结
    团队开发冲刺日(十二)
    团队开发冲刺日(十一)
    团队开发冲刺日(十)
    团队开发冲刺日(九)
    团队开发冲刺日(八)
    团队开发冲刺日(七)
    团队开发冲刺日(六)
    课后作业1
  • 原文地址:https://www.cnblogs.com/qiaozhoulin/p/4574728.html
Copyright © 2020-2023  润新知