本人一直在努力地积累Leetcode上用Python, C++实现的题,并且会尽力讲清每道题的原理,绝不像其他某些博客简略地带过。
如果觉得讲的清楚,欢迎关注。
题目:
实现 int sqrt(int x)
函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4 输出: 2
示例 2:
输入: 8 输出: 2 说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
又是一道python比较无敌的题。。。
不得不感慨,C++的难度与python相比绝对是一个天上一个地下。(近期坚持用C++刷题后的感慨)
方法一:利用库函数法(这种方法简直侮辱智商,所以也不写注释了)
import math
class Solution:
def mySqrt(self, x):
"""
:type x: int
:rtype: int
"""
return int(math.sqrt(x))
方法二:二分法(题目提示的方法)
class Solution:
def mySqrt(self, x):
"""
:type x: int
:rtype: int
"""
low = 0
high = x
mid = x // 2
while low <= high:
if mid*mid == x:
return mid
if mid*mid < x:
low = mid + 1
else:
high = mid - 1
mid = (low + high) // 2
return mid
熟悉的二分算法。这里要说的是在临界情况下,当low == high 并且依然mid*mid != x时,这时候根据情况会是mid*mid < x,因为要求的是平方根所以不会大于。最后更新的mid还是原来的mid,因为low+1后//2对最终mid没有影响。
方法三:牛顿迭代法:
class Solution:
def mySqrt(self, x):
"""
:type x: int
:rtype: int
"""
s = x
while (s*s - x < 0.000001):
s = (s + s/x)/2
return int(x)
无数算法教科书都介绍过的算法,也确实有二分的意思。
方法四:C++法(。。。这篇文章真的水)
class Solution {
public:
int mySqrt(int x) {
if (x <= 1) return x;
int left = 0, right = x;
while (left < right) {
int mid = left + (right - left) / 2;
if (x / mid >= mid) left = mid + 1;
else right = mid;
}
return right - 1;
}
};
是python的二分的C++版本。
总结:今天说一个细节的问题,二分的时候while 语句 < 和 <= 号的选择,以及更新low ,high (left, right)时的要不要加一的问题。这个问题有时还是真的一直在迷惑着我。就像这2个2分代码,就是这2种不同思路的体现。
while 里是<号的时候,整体思路是把low ,high 看成一个左闭右开的区间,所以high 不会等于low,一等于就什么也得不到了。
所以说right = mid,也就是说mid在开的位置上,实际上也是抛弃了mid这个选项了。而如果是<= 说明是左闭右闭,这种情况更新right时应该是right = mid - 1。