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;
	}
};
这种方法是正确的,因为它是游戏引擎中的源码,所以不用验证都可以知道其正确性。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值