LeetCode 69

    Sqrt(x)

    没错,有几天没写LeetCode了,就遇上了sqrt函数的编写,这是不是很简单呢?于是我很快的想出了遍历的方法,但是马上又想到了若是一个最大的整数位测试用例呢?那么效率太低了吧,于是我以效率为出发点又想到了二分法,使用二分法自己测试了几个,感觉还可以,于是就提交了,代码如下:

class Solution
{
public:
	int mySqrt(int x)
	{
		//二分法
		assert(x >= 0);
		//1.特殊情况
		if (x == 0 || x == 1)
		{
			return x;
		}

		//2.一般情况
		int left = 0;
		int right = x;
		int mid = (left + right) / 2;
		while (mid*mid > x || (mid+1)*(mid+1) <= x)
		{
			if (mid * mid > x)
			{
				right = mid;
			}
			else if ( (mid + 1) * (mid + 1) <= x)
			{
				left = mid;
			}
			mid = (left + right) / 2;
		}

		return mid;
	}
};
测试用例卡在了2147395599上面,结果如下:



出现这种结果说明二分法还是不够优化,那么我们所能想到的办法还有什么呢?我感觉真的是想不出来,于是我在网上看了一些文章,将关于sqrt函数的问题,于是我找到了一种求解方法,利用到的思想是”牛顿迭代法快速寻找平方根“,其思想是利用高数中的思想:求 X^2 - a = 0 的根,这些思想若是没有学习过真的是想不出来的,我是参考一篇文章,所以最后我会将这篇文章贴出来,分享给大家。

使用牛顿迭代快速寻找平方根的思想,我们可以写出下列代码:

class Solution
{
public:
	int mySqrt(int x)
	{
		//牛顿迭代法
		assert(x >= 0);
		if (x == 0 || x == 1)
		{
			return x;
		}
		
		float val = x;   //最终
		float last;		//保存上一个计算的值
		
		do{
			last = val;
			val = (val + x / val) / 2;
		} while (abs(val - last) > 0.01); //因为这个题的最终结果是整数,所以我们可以将精度提高点

		int ret = (int)val;
		if (ret*ret > x)
		{
			return ret - 1;
		}
		else
		{
			return ret;
		}
	}
};
这个函数最终被接收了,结果如下:


其实到这里还没完呢?有些人真的是大神,他们只要两步就可以求出一个数的平方根,他的思路我还没弄明白,因为源码是某游戏引擎的代码,不过这里还是将他的代码贴出来,跟大家分享一下:

class Solution
{
public:
	int mySqrt(int x)
	{
		//数学大神根据牛顿迭代法来求推导出的神奇方法
		assert(x >= 0);
		if (x == 0 || x == 1)
		{
			return x;
		}
		float tmp = x;
		float xhalf = 0.5f*tmp;
		int i = *(int*)&tmp;
		
		i = 0x5f375a86 - (i >> 1); // 这一步是关键
		
		tmp = *(float*)&i;
		tmp = tmp*(1.5f - xhalf*tmp*tmp);
		tmp = tmp*(1.5f - xhalf*tmp*tmp);
		tmp = tmp*(1.5f - xhalf*tmp*tmp);

		int ret = 1 / tmp;
		if (ret*ret > x)
		{
			return ret - 1;
		}
		return ret;
	}
};
这种方法是正确的,因为它是游戏引擎中的源码,所以不用验证都可以知道其正确性。

    我个人觉得这种类型的题真的是很吃数学功底,也道题很彻底的让我感受到了数学的强大,让我深受感触。下面我就给出我看过的文章的出处:参考文章

发布了194 篇原创文章 · 获赞 88 · 访问量 45万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章