Recently sneak brush every day to maintain a LeetCode simple questions feel, though simple question easily find AC, but if to understand all of its solution, but also to learn a lot of new knowledge, expand the breadth of knowledge.
This article comes from the idea of creation: the square root of LeetCode Problem 69. x
DESCRIPTION Title effect (do not want to jump links, can be seen here): Given a non-negative integer x , and returns the computing requirements x square root of (rounded). For example, 4 input, output 2; 8 input, output 2 (2.82842 square root ...... 8 is, since the return type is an integer, the fractional part is discarded). I.e. given a \ (X \) , we have to calculate the \ (\ lfloor \ sqrt {X} \ rfloor \) .
The simplest and most intuitive way to naturally traversing from 0, until the first of its squared value greater than \ (X \) is the number of \ (n-\) , then \ (n-1 \) that is the answer. For any \ (X \) , after which the square root must be in rounding \ ([0, x] \ ) on the interval, as follows:
int sqrt(int x)
{
if (x == 0)
return x;
int ans = 1;
while (ans <= x / ans)
ans++;
return ans - 1;
}
There are two points to note here:
- Code line 6,
while
the determination condition to avoid overflow. The probability of large, you might writewhile (ans * ans <= x)
, it is more natural, more intuitive, butans
a lot of the time value,ans * ans
the result may exceed theint
type of representation the maximum range. For example, we have to calculate such \ (X \) is the square root of rounding (which is \ (n-\) , i.e., \ (\ lfloor \ sqrt {X} \ = n-rfloor \) ), the algorithm willans
traverse to a first square exceeds \ (X \) values, i.e. \ (n + 1 \) stopped. If \ (X \) value is theint
maximum value that can be represented type, then whenans
traversed \ (n + 1 \) , the calculationans * ans
result to exceed theint
type represented range. - Since the
while
cycle of judgment, we use division instead of multiplication, and thereforeans
can no longer be traversing from 0 (otherwise it will lead to division by zero). To this end, we can handle alone at the beginning of the algorithm \ (x = 0 \) situation, and then letans
starting from 1 traversal.
As a simple question, such violence is a natural simple algorithm of AC. But its low efficiency (need to traverse \ (O (\ sqrt {n }) \) times), the time efficiency in LeetCode only about 5% faster than the user, using the C ++ language runtime average more than 90ms. Therefore, this article provides two more efficient algorithms: binary search method and Newton method.
1. binary search
If you continue to think about violence on the basis of solving the great probability would have thought solved by binary search.
Yes, thinking strategies to solve the violence, we are in the interval \ ([0, x] \ ) search for a solution, rather search domain \ ([0, x] \ ) is naturally ordered, naturally you can use binary search instead of linear Search to significantly improve search efficiency.
Furthermore, we can narrow our search range. Intuition tells us that, for a non-negative integer \ (X \) , which \ (\ sqrt {x} \ ) should not be greater than \ (X / 2 \) (for example, \ (\ = sqrt {25}. 5 \) , less than \ (25/2 = 12.5 \) ). We can prove that:
\ [\ Begin {aligned} & \ text {set} y = \ frac {x} {2} - \ sqrt {x}, \ text {the} y ^ \ prime = \ frac {1} {2} - \ frac {1} {2 \ sqrt {x}}, \\ [2ex] & \ text {so} y ^ \ prime = 0, \ text {available stagnation} x = 1, \\ [2ex] & \ text {if} x> 1 \ {when} text, y ^ \ prime> 0, \ text {i.e. when} x> 1 \ {when} text, y = \ frac {x} {2} - \ sqrt {x } \ text {monotonically increasing value}, \\ [2ex] & \ text {to be launched, when} x> 1 \ when the text {}, \ lfloor \ frac {x} {2} \ rfloor - \ lfloor \ sqrt {x} \ rfloor \ text {monotonically increasing value}, \\ [2ex] & \ text {and because when} x = 2 \ {when} text, \ lfloor \ frac {x} {2} \ rfloor - \ lfloor \ sqrt {x} \ rfloor = 0, \\ [2ex] & \ text {so when} x \ geq 2 \ {when} text, \ lfloor \ frac {x} {2} \ rfloor - \ lfloor \ sqrt {x} \ rfloor \ geq 0, \ text {i.e.} x \ geq 2 \ {when} text, \ lfloor \ frac {x} {2} \ rfloor \ geq \ lfloor \ sqrt {x} \ rfloor & \ text {(QED)} \ end {aligned} \]
By proving we can see that, when the request of \ (X \) greater than or equal \ (2 \) , the sqrt(x)
search space for the \ ([. 1, X / 2] \) , for \ (x <2 \) case , we only to special treatment (here we can conclude: when \ (x \ geq 1 \) when, \ (\ lfloor \ X FRAC} {2} {\ + rfloor. 1 \ GEQ \ lfloor \ sqrt {X } \ rfloor \) , then treated separately \ (x <1 \) case). Code:
int sqrt(int x)
{
if (x < 2) // 处理特殊情况
return x;
int left = 1, right = x / 2;
while (left <= right) {
# 避免溢出,相当于 mid = (left + right) / 2
int mid = left + ((right - left) >> 1);
if (mid == x / mid)
return mid;
else if (mid > x / mid)
right = mid - 1;
else
left = mid + 1;
}
return right;
}
Here to explain the last return value why right
. For the binary search, it will continue to shrink to a search space left == right
(on a binary search, much repeated here, can themselves manually analog), In this case mid
, left
and right
the value is equal to three ( mid = (left + right) / 2
). The retracted condition of the search range of known binary search, left
(or mid
), on the left are less \ (\ lfloor \ sqrt {X} \ rfloor \) , right
(or mid
) the right value greater than \ (\ lfloor \ sqrt X} {\ rfloor \) , at this time ( while
the last cycle) determines mid
the square of x
the size, there are three cases:
mid == x / mid
. Directly in the circulation returnmid
value.mid > x / mid
. In this case, sincemid
the value of the left side are less \ (\ lfloor \ sqrt {X} \ rfloor \) , and themid
value is greater than \ (X \) , thenmid-1
that is the answer. The branch in accordance with the conditions, executionright = mid - 1
, we can seeright
the value of what value should be returned. In this case, the end of the cycle, should be returnedright
.mid <= x / mid
. In this casemid
,left
andright
it is calculated answer (right value greater than \ (\ lfloor \ sqrt {X} \ rfloor \) ). A branching conditions, executionleft = mid + 1
, ending cycle. At this time,mid
andright
a value of the calculation result.
Integrated the above three can be seen, if while
the cycle is completed, the right
stored value must be calculated results.
And before Violence compared using a binary thought to find solving sqrt(x)
only loop through \ (O (\ lg {\ frac {x} {2}}) \) times; complex spatial degree \ (O (1) \ ) .
2. Newton - Raphson iteration method
Newton - Raphson iterative method (referred to as Newton's method) using the method to straight thinking on behalf of the song, is a function of solving, not just for solving the square root calculation. Of course, using Newton's method to solve a function there are many pits, but for solving evolution, the Newton's method is safe. On this method, you need to have some knowledge of higher mathematics, want to know details, refer to the link: How to explain in plain Newton iterative method for evolution? data analysis? - MA students answer
Simple to understand, you can refer to picture:
Given an arbitrary non-negative integer \ (n-\) , we want to find a \ (X = \ lfloor \ n-sqrt {} \ rfloor \) , which is equivalent to the function we want to calculate \ (f (x) = x ^ 2 - n \) root. First, we need to give a guess \ (x_0 \) , might make \ (x_0 = \ FRAC {X} + {2}. 1 \) (see the first measure proof), then \ (f (x_0) \ ) tangent as a function of the tangent of (X \) \ intersection axis that is a value after iterations \ (x_1 \) . If \ (x_1 \) the result is not to be obtained, the iteration is continued, in \ (f (x_1) \) tangent as a function of the tangent and \ (X \) the intersection of the axes, namely after the second iteration value \ (x_2 \) . And so on, until \ (x_n = \ lfloor \ n-sqrt {} \ rfloor \) .
Now we derive iterative. For \ (x_i \) , which is the function value \ (F (x_i) \) , then for point \ ((x_i, F (x_i)) \) , can be lent tangent equation:
\[ \begin{align} &y - f(x_i) = f(x_i)^\prime(x - x_i) \\[2ex] \implies &y - (x_i^2 - n) = 2x_i(x - x_i) \\[2ex] \implies &y + x_i^2 + n = 2x_ix \end{align} \]
And because \ (x_ {i + 1} \) is a tangent (X \) \ intersection of the axis, so that it \ (Y = 0 \) , can be obtained:
\[ x_{i+1} = (x_i + n / x_i) / 2 \]
Now, we can write code in accordance with iterative:
int sqrt(int x)
{
// 避免除零错误,单独处理 x = 0 的情况
if (x == 0)
return x;
int t = x / 2 + 1;
while (t > x / t)
t = (t + x / t) / 2;
return t;
}
In order to ensure that the algorithm is correct, we need some additional proof. First of all, it proves iterative monotonically decreasing:
\[ x_{i+1} - x_i = \left\lfloor \frac{1}{2} (x_i + \frac{n}{x_i}) \right\rfloor - x_i = \left\lfloor \frac{1}{2} (\frac{n}{x_i} - x_i) \right\rfloor \]
Found that in the interval \ ([\ sqrt {x} , + \ infty) \) a, \ (. 1 + X_ {I} - x_i <0 \) .
Then, we have to prove iterative can converge to \ (\ lfloor \ sqrt {n } \ rfloor \) of:
\[ x_{i+1} = \left\lfloor \frac{1}{2} \left( x_i + \left\lfloor \frac{n}{x_i} \right\rfloor \right) \right\rfloor = \left \lfloor \frac{1}{2} (x_i + \frac{n}{x_i}) \right \rfloor \geq \left \lfloor \frac{1}{2} \times 2 \times \sqrt{x_i \cdot \frac{n}{x_i}} \right \rfloor = \lfloor \sqrt{n} \rfloor \]
Therefore, when the while
end of the cycle, we can get the right answers.
About Newton's law seeking sqrt(x)
the complexity of the time, the author is also not clear, there is understanding of children's shoes please share ~. But by querying the data, as well as the actual test, we can see the time efficiency of Newton's method is superior to the binary search algorithm.