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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章