题目如下:
Implement int sqrt(int x).
Compute and return the square root of x.
分析如下:
(1)借助一个小结论,任何一个数的square都在大于等于1,小于x/2+1。很容易反证。
(2)第一次提交,发现溢出了。因为不是low, hight, mid用的类型是int,所以mid*mid可能会溢出。所以应该把数据类型设为long long。
(3)本质思想还是二分查找。
我的代码:
class Solution { public: int sqrt(int x) { long long low=1; long long high=x/2+1; long long mid=0; if(x==1) return 1; if(x<=0) return 0; while(low<=high){ //这里是low<=high而不是low<high,理由是,当low=high时,可能还没找到正确值,需要在进入循环体更新一次。可用sqrt(5)来验证。 mid=low+(high-low)/2; if(mid*mid>x) high=mid-1; else if(mid*mid<x) low=mid+1; else return mid; } return (low+high)/2;//注意这里是返回新的mid,也就是(low+high)/2,而不是旧的mid。如果写return mid,就将返回旧的mid,有错。 } };
update 2014-12-30
解法一: 迭代
/* *解法一:迭代 *1. 一个数n的平方根一定小于等于(n/2 + 1), 二分法查找(递归和迭代)。 *2. 可能是平台的问题,如果用unsinged long long 而不是long long型的话,答案会有问题。 *3. while(start <=end)这里的条件是“小于等于”。 4. 迭代到最后,可能出现的情况打印出来看有两种,观察可以发现,循环结束的时候, sqrt = start - 1。 case 1:达到相等点之后走向相等点的左边 input=5 start = 1, end = 3, mid = 2 start = 3, end = 3, mid = 3 //达到相等点(3)之后走向相等点的左边 start = 3, end = 2, x = 5 real sqrt=2, my sqrt =2 case 2:不达到相等点,直接走向相等点的左边 input=6 start = 1, end = 4, mid = 2 start = 3, end = 4, mid = 3 //不达到相等点,到达两个相邻点(3, 4), 直接走向相邻点的左边 start = 3, end = 2, x = 6 real sqrt=2, my sqrt =2 */ //84ms class Solution { public: long long sqrt(long long x, long long start, long long end) { while (start <= end) { long long mid = start + (end - start) / 2; //std::cout<<"start = "<<start<<", end = "<<end<<", mid = "<<mid<<std::endl; if (mid * mid == x) return mid; else if (mid * mid > x) end = mid - 1; else start = mid + 1; } //std::cout<<"start = "<<start << ", end = "<<end<<", x = " << x<<std::endl; return start - 1; } int sqrt(int x) { if (x < 0) return -1; if (x == 0) return 0; if (x == 1) return 1; return (int)sqrt(x, 1, x/2 + 1); } };
解法二: 递归看上更好懂,可以避免处理循环结束时候的情况。
//解法二: 递归 //84ms class Solution { public: long long sqrt(long long x, long long start, long long end) { long long mid = start + (end - start)/2; if (mid * mid <= x && (mid + 1) * (mid + 1) > x) return mid; else if (mid * mid > x) return sqrt(x, start, mid-1); else if (mid * mid < x) return sqrt(x, mid + 1, end); } int sqrt(int x) { if (x < 0) return -1; if (x == 0) return 0; if (x == 1) return 1; return (int)sqrt(x, 1, x); } };
//解法3: newton's method //76ms class Solution { public: long long sqrt_my(long long x) { long long guess = x/2 + 1; //注意这里不能写错数据类型,如果long long写为long或者int都会导致错误。 while (1) { if (guess * guess <= x && (guess + 1) * (guess + 1) > x) return guess; guess =(guess + x/guess)/2; } } int sqrt(int x) { return sqrt_my((long long)x); } };