因为是查找某个数的问题,查找范围有着明确的上下界,所以这道题用二分的思想求解。需要注意到特殊情况0和1,所以左右边界分别为0和x,而不是1和(x-1)。
现在需要考虑一下什么时候算是找到正确答案了。先看以下表格
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 3 |
可以发现,在平方数4和9之间的所有数的正确答案均为2。所以如果mid为正确答案,那么目标x就一定在
m
i
d
∗
m
i
d
mid*mid
mid∗mid和
(
m
i
d
+
1
)
∗
(
m
i
d
+
1
)
(mid+1)*(mid+1)
(mid+1)∗(mid+1)之间,左闭右开。
如果mid不为正确答案,那么可能在mid左半部分或右半部分,现在就是判断在左半部分或右半部分。如果使mid为正确答案的区间在x的左边,也就是
(
m
i
d
+
1
)
∗
(
m
i
d
+
1
)
<
=
g
o
a
l
(mid+1)*(mid+1)<=goal
(mid+1)∗(mid+1)<=goal,那么就说明mid选小了,要将
l
e
f
t
=
m
i
d
+
1
left=mid+1
left=mid+1,在右半部分继续搜索;如果mid为正确答案的区间在x的右边,也就是
m
i
d
∗
m
i
d
>
g
o
a
l
mid*mid>goal
mid∗mid>goal,那么就说明mid选大了,要将
r
i
g
h
t
=
m
i
d
−
1
right=mid-1
right=mid−1,在左半部分继续搜索。
由于选左半部分、选右半部分和选到正确答案这三种情况是互斥的,所以只要判断两种情况,另一种情况用else判断即可。本代码种判断了选到正确答案和选左半部分的情况,选右半部分的情况用else判断。
class Solution:
def BinarySearch(self, left: int, right: int, goal: int) -> int:
while left <= right:
mid = (left+right)//2
if mid*mid <= goal and (mid+1)*(mid+1) > goal:
return mid
if mid*mid > goal:
right = mid-1
else:
left = mid+1
return -1
def mySqrt(self, x: int) -> int:
return self.BinarySearch(0, x, x)