Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 44 additions & 64 deletions solution/0300-0399/0367.Valid Perfect Square/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ tags:

### 方法一:二分查找

不断循环二分枚举数字,判断该数的平方与 `num` 的大小关系,进而缩短空间,继续循环直至 $left \lt right$ 不成立。循环结束判断 $left^2$ 与 `num` 是否相等
我们可以使用二分查找来解决这个问题。定义二分查找的左边界 $l = 1$,右边界 $r = num$,然后在 $[l, r]$ 的范围内查找满足 $x^2 \geq num$ 的最小整数 $x$。最后,如果 $x^2 = num$,则说明 $num$ 是一个完全平方数

时间复杂度$O(logN)$。
时间复杂度 $O(\log n)$,其中 $n$ 是给定的数字。空间复杂度 $O(1)$。

<!-- tabs:start -->

Expand All @@ -68,31 +68,25 @@ tags:
```python
class Solution:
def isPerfectSquare(self, num: int) -> bool:
left, right = 1, num
while left < right:
mid = (left + right) >> 1
if mid * mid >= num:
right = mid
else:
left = mid + 1
return left * left == num
l = bisect_left(range(1, num + 1), num, key=lambda x: x * x) + 1
return l * l == num
```

#### Java

```java
class Solution {
public boolean isPerfectSquare(int num) {
long left = 1, right = num;
while (left < right) {
long mid = (left + right) >>> 1;
if (mid * mid >= num) {
right = mid;
int l = 1, r = num;
while (l < r) {
int mid = (l + r) >>> 1;
if (1L * mid * mid >= num) {
r = mid;
} else {
left = mid + 1;
l = mid + 1;
}
}
return left * left == num;
return l * l == num;
}
}
```
Expand All @@ -103,15 +97,16 @@ class Solution {
class Solution {
public:
bool isPerfectSquare(int num) {
long left = 1, right = num;
while (left < right) {
long mid = left + right >> 1;
if (mid * mid >= num)
right = mid;
else
left = mid + 1;
int l = 1, r = num;
while (l < r) {
int mid = l + (r - l) / 2;
if (1LL * mid * mid >= num) {
r = mid;
} else {
l = mid + 1;
}
}
return left * left == num;
return 1LL * l * l == num;
}
};
```
Expand All @@ -120,61 +115,44 @@ public:

```go
func isPerfectSquare(num int) bool {
left, right := 1, num
for left < right {
mid := (left + right) >> 1
if mid*mid >= num {
right = mid
} else {
left = mid + 1
}
}
return left*left == num
l := sort.Search(num, func(i int) bool { return i*i >= num })
return l*l == num
}
```

#### TypeScript

```ts
function isPerfectSquare(num: number): boolean {
let left = 1;
let right = num >> 1;
while (left < right) {
const mid = (left + right) >>> 1;
if (mid * mid < num) {
left = mid + 1;
let [l, r] = [1, num];
while (l < r) {
const mid = (l + r) >> 1;
if (mid >= num / mid) {
r = mid;
} else {
right = mid;
l = mid + 1;
}
}
return left * left === num;
return l * l === num;
}
```

#### Rust

```rust
use std::cmp::Ordering;
impl Solution {
pub fn is_perfect_square(num: i32) -> bool {
let num: i64 = num as i64;
let mut left = 1;
let mut right = num >> 1;
while left < right {
let mid = left + (right - left) / 2;
match (mid * mid).cmp(&num) {
Ordering::Less => {
left = mid + 1;
}
Ordering::Greater => {
right = mid - 1;
}
Ordering::Equal => {
return true;
}
let mut l = 1;
let mut r = num as i64;
while l < r {
let mid = (l + r) / 2;
if mid * mid >= (num as i64) {
r = mid;
} else {
l = mid + 1;
}
}
left * left == num
l * l == (num as i64)
}
}
```
Expand All @@ -185,11 +163,11 @@ impl Solution {

<!-- solution:start -->

### 方法二:转换为数学问题
### 方法二:数学

由于 `n² = 1 + 3 + 5 + ... + (2n-1)`,对数字 `num` 不断减去 $i$ (`i = 1, 3, 5, ...`) 直至 `num` 不大于 0,如果最终 `num` 等于 0,说明是一个有效的完全平方数
由于 $1 + 3 + 5 + \cdots + (2n - 1) = n^2$,我们可以将 $num$ 逐渐减去 $1, 3, 5, \cdots$,如果最后 $num = 0$,则说明 $num$ 是一个完全平方数

时间复杂度$O(sqrt(N))$。
时间复杂度 $O(\sqrt n)$,空间复杂度 $O(1)$。

<!-- tabs:start -->

Expand Down Expand Up @@ -224,7 +202,9 @@ class Solution {
class Solution {
public:
bool isPerfectSquare(int num) {
for (int i = 1; num > 0; i += 2) num -= i;
for (int i = 1; num > 0; i += 2) {
num -= i;
}
return num == 0;
}
};
Expand Down
119 changes: 47 additions & 72 deletions solution/0300-0399/0367.Valid Perfect Square/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ tags:

<!-- solution:start -->

### Solution 1: Binary search
### Solution 1: Binary Search

We can use binary search to solve this problem. Define the left boundary $l = 1$ and the right boundary $r = num$ of the binary search, then find the smallest integer $x$ that satisfies $x^2 \geq num$ in the range $[l, r]$. Finally, if $x^2 = num$, then $num$ is a perfect square.

The time complexity is $O(\log n)$, where $n$ is the given number. The space complexity is $O(1)$.

<!-- tabs:start -->

Expand All @@ -62,31 +66,25 @@ tags:
```python
class Solution:
def isPerfectSquare(self, num: int) -> bool:
left, right = 1, num
while left < right:
mid = (left + right) >> 1
if mid * mid >= num:
right = mid
else:
left = mid + 1
return left * left == num
l = bisect_left(range(1, num + 1), num, key=lambda x: x * x) + 1
return l * l == num
```

#### Java

```java
class Solution {
public boolean isPerfectSquare(int num) {
long left = 1, right = num;
while (left < right) {
long mid = (left + right) >>> 1;
if (mid * mid >= num) {
right = mid;
int l = 1, r = num;
while (l < r) {
int mid = (l + r) >>> 1;
if (1L * mid * mid >= num) {
r = mid;
} else {
left = mid + 1;
l = mid + 1;
}
}
return left * left == num;
return l * l == num;
}
}
```
Expand All @@ -97,15 +95,16 @@ class Solution {
class Solution {
public:
bool isPerfectSquare(int num) {
long left = 1, right = num;
while (left < right) {
long mid = left + right >> 1;
if (mid * mid >= num)
right = mid;
else
left = mid + 1;
int l = 1, r = num;
while (l < r) {
int mid = l + (r - l) / 2;
if (1LL * mid * mid >= num) {
r = mid;
} else {
l = mid + 1;
}
}
return left * left == num;
return 1LL * l * l == num;
}
};
```
Expand All @@ -114,61 +113,44 @@ public:

```go
func isPerfectSquare(num int) bool {
left, right := 1, num
for left < right {
mid := (left + right) >> 1
if mid*mid >= num {
right = mid
} else {
left = mid + 1
}
}
return left*left == num
l := sort.Search(num, func(i int) bool { return i*i >= num })
return l*l == num
}
```

#### TypeScript

```ts
function isPerfectSquare(num: number): boolean {
let left = 1;
let right = num >> 1;
while (left < right) {
const mid = (left + right) >>> 1;
if (mid * mid < num) {
left = mid + 1;
let [l, r] = [1, num];
while (l < r) {
const mid = (l + r) >> 1;
if (mid >= num / mid) {
r = mid;
} else {
right = mid;
l = mid + 1;
}
}
return left * left === num;
return l * l === num;
}
```

#### Rust

```rust
use std::cmp::Ordering;
impl Solution {
pub fn is_perfect_square(num: i32) -> bool {
let num: i64 = num as i64;
let mut left = 1;
let mut right = num >> 1;
while left < right {
let mid = left + (right - left) / 2;
match (mid * mid).cmp(&num) {
Ordering::Less => {
left = mid + 1;
}
Ordering::Greater => {
right = mid - 1;
}
Ordering::Equal => {
return true;
}
let mut l = 1;
let mut r = num as i64;
while l < r {
let mid = (l + r) / 2;
if mid * mid >= (num as i64) {
r = mid;
} else {
l = mid + 1;
}
}
left * left == num
l * l == (num as i64)
}
}
```
Expand All @@ -179,20 +161,11 @@ impl Solution {

<!-- solution:start -->

### Solution 2: Math trick
### Solution 2: Mathematics

This is a math problem:
Since $1 + 3 + 5 + \cdots + (2n - 1) = n^2$, we can gradually subtract $1, 3, 5, \cdots$ from $num$. If $num$ finally equals $0$, then $num$ is a perfect square.

```bash
1 = 1
4 = 1 + 3
9 = 1 + 3 + 5
16 = 1 + 3 + 5 + 7
25 = 1 + 3 + 5 + 7 + 9
36 = 1 + 3 + 5 + 7 + 9 + 11
....
so 1+3+...+(2n-1) = (2n-1 + 1)n/2 = n²
```
The time complexity is $O(\sqrt n)$, and the space complexity is $O(1)$.

<!-- tabs:start -->

Expand Down Expand Up @@ -227,7 +200,9 @@ class Solution {
class Solution {
public:
bool isPerfectSquare(int num) {
for (int i = 1; num > 0; i += 2) num -= i;
for (int i = 1; num > 0; i += 2) {
num -= i;
}
return num == 0;
}
};
Expand Down
Loading