Skip to content

Commit 42924c6

Browse files
authored
feat: add solution to lc problem: No.3235 (#3704)
1 parent 39584f5 commit 42924c6

File tree

4 files changed

+339
-2
lines changed

4 files changed

+339
-2
lines changed

solution/3200-3299/3235.Check if the Rectangle Corner Is Reachable/README.md

+127-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,43 @@ tags:
102102

103103
<!-- solution:start -->
104104

105-
### 方法一
105+
### 方法一:DFS + 数学
106+
107+
根据题意,我们分情况讨论:
108+
109+
`circles` 中只有一个圆时:
110+
111+
1. 如果起点 $(0, 0)$ 在圆内(包括边界),或者终点 $(\textit{xCorner}, \textit{yCorner})$ 在圆内,那么无法满足“不触碰圆”的条件;
112+
1. 如果圆与矩形的左侧或上侧有交点,且与矩形的右侧或下侧有交点,这种情况下,圆会阻断从矩形左下角到右上角的路径,也无法满足“不触碰圆”的条件。
113+
114+
`circles` 中有多个圆时:
115+
116+
1. 与上述情况类似,如果起点或终点在圆内时,无法满足“不触碰圆”的条件。
117+
2. 如果有多个圆,多个圆之间可能在矩形内相交,合并形成更大的障碍区域。只要这个障碍区域与矩形的左侧或上侧有交点,且与矩形的右侧或下侧有交点,那么无法满足“不触碰圆”的条件。如果相交区域不在矩形内部,不能进行合并,因为相交的区域无法阻断矩形内部路径。另外,如果相交的区域有一部分在矩形内,有一部分在矩形外,这些圆都可以作为搜索的起点或终点,可以合并,也可以不合并。我们只要任选相交的其中一个点,如果这个点在矩形内,我们就可以将这些圆合并。
118+
119+
根据上述分析,我们遍历所有圆,对于当前遍历到的圆,如果起点或终点在圆内,我们直接返回 `false`。否则,如果这个点没有被访问过,且这个圆与矩形的左侧或上侧有交点,我们就从这个圆开始进行深度优先搜索,搜索过程中,如果找到了一个圆,它与矩形的右侧或下侧有交点,说明圆形成的障碍区域阻断了从矩形左下角到右上角的路径,我们就返回 `false`
120+
121+
我们定义 $\textit{dfs}(i)$ 表示从第 $i$ 个圆开始进行深度优先搜索,如果找到了一个圆,它与矩形的右侧或下侧有交点,返回 `true`,否则返回 `false`
122+
123+
函数 $\textit{dfs}(i)$ 的执行过程如下:
124+
125+
1. 如果当前圆与矩形的右侧或下侧有交点,返回 `true`
126+
1. 否则,我们将当前圆标记为已访问;
127+
1. 接下来,遍历其它所有圆,如果圆 $j$ 没被访问过,且圆 $i$ 和圆 $j$ 相交,且这两个圆的其中一个交点在矩形内,我们就继续从圆 $j$ 开始进行深度优先搜索,如果找到了一个圆,它与矩形的右侧或下侧有交点,返回 `true`
128+
1. 如果没有找到这样的圆,返回 `false`
129+
130+
上面的过程中,我们需要在圆 $O_1 = (x_1, y_1, r_1)$ 和 $O_2 = (x_2, y_2, r_2)$ 之间判断是否相交,如果两个圆相交,那么它们的圆心之间的距离不超过两个圆的半径之和,即 $(x_1 - x_2)^2 + (y_1 - y_2)^2 \le (r_1 + r_2)^2$。
131+
132+
我们还需要寻找两个圆的一个交点,我们取一个点 $A = (x, y)$,满足 $\frac{O_1 A}{O_1 O_2} = \frac{r_1}{r_1 + r_2}$,如果两圆相交,那么点 $A$ 一定在交集中,此时 $\frac{x - x_1}{x_2 - x_1} = \frac{r_1}{r_1 + r_2}$,解得 $x = \frac{x_1 r_2 + x_2 r_1}{r_1 + r_2}$,同理,有 $y = \frac{y_1 r_2 + y_2 r_1}{r_1 + r_2}$。只要这个点在矩形内,我们就可以继续进行深度优先搜索,即满足:
133+
134+
$$
135+
\begin{cases}
136+
x_1 r_2 + x_2 r_1 < (r_1 + r_2) \times \textit{xCorner} \\
137+
y_1 r_2 + y_2 r_1 < (r_1 + r_2) \times \textit{yCorner}
138+
\end{cases}
139+
$$
140+
141+
时间复杂度 $O(n^2)$,空间复杂度 $O(n)$。其中 $n$ 为圆的数量。
106142

107143
<!-- tabs:start -->
108144

@@ -416,6 +452,96 @@ function canReachCorner(xCorner: number, yCorner: number, circles: number[][]):
416452
}
417453
```
418454

455+
#### Rust
456+
457+
```rust
458+
impl Solution {
459+
pub fn can_reach_corner(x_corner: i32, y_corner: i32, circles: Vec<Vec<i32>>) -> bool {
460+
let n = circles.len();
461+
let mut vis = vec![false; n];
462+
463+
let in_circle = |x: i64, y: i64, cx: i64, cy: i64, r: i64| -> bool {
464+
(x - cx) * (x - cx) + (y - cy) * (y - cy) <= r * r
465+
};
466+
467+
let cross_left_top = |cx: i64, cy: i64, r: i64| -> bool {
468+
let a = cx.abs() <= r && (cy >= 0 && cy <= y_corner as i64);
469+
let b = (cy - y_corner as i64).abs() <= r && (cx >= 0 && cx <= x_corner as i64);
470+
a || b
471+
};
472+
473+
let cross_right_bottom = |cx: i64, cy: i64, r: i64| -> bool {
474+
let a = (cx - x_corner as i64).abs() <= r && (cy >= 0 && cy <= y_corner as i64);
475+
let b = cy.abs() <= r && (cx >= 0 && cx <= x_corner as i64);
476+
a || b
477+
};
478+
fn dfs(
479+
circles: &Vec<Vec<i32>>,
480+
vis: &mut Vec<bool>,
481+
i: usize,
482+
x_corner: i32,
483+
y_corner: i32,
484+
cross_right_bottom: &dyn Fn(i64, i64, i64) -> bool,
485+
) -> bool {
486+
let c = &circles[i];
487+
let (x1, y1, r1) = (c[0] as i64, c[1] as i64, c[2] as i64);
488+
489+
if cross_right_bottom(x1, y1, r1) {
490+
return true;
491+
}
492+
493+
vis[i] = true;
494+
495+
for j in 0..circles.len() {
496+
if vis[j] {
497+
continue;
498+
}
499+
500+
let c2 = &circles[j];
501+
let (x2, y2, r2) = (c2[0] as i64, c2[1] as i64, c2[2] as i64);
502+
503+
if (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) > (r1 + r2) * (r1 + r2) {
504+
continue;
505+
}
506+
507+
if x1 * r2 + x2 * r1 < (r1 + r2) * x_corner as i64
508+
&& y1 * r2 + y2 * r1 < (r1 + r2) * y_corner as i64
509+
&& dfs(circles, vis, j, x_corner, y_corner, cross_right_bottom)
510+
{
511+
return true;
512+
}
513+
}
514+
false
515+
}
516+
517+
for i in 0..n {
518+
let c = &circles[i];
519+
let (x, y, r) = (c[0] as i64, c[1] as i64, c[2] as i64);
520+
521+
if in_circle(0, 0, x, y, r) || in_circle(x_corner as i64, y_corner as i64, x, y, r) {
522+
return false;
523+
}
524+
525+
if !vis[i]
526+
&& cross_left_top(x, y, r)
527+
&& dfs(
528+
&circles,
529+
&mut vis,
530+
i,
531+
x_corner,
532+
y_corner,
533+
&cross_right_bottom,
534+
)
535+
{
536+
return false;
537+
}
538+
}
539+
540+
true
541+
}
542+
}
543+
```
544+
419545
<!-- tabs:end -->
420546

421547
<!-- solution:end -->

solution/3200-3299/3235.Check if the Rectangle Corner Is Reachable/README_EN.md

+127-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,43 @@ tags:
100100

101101
<!-- solution:start -->
102102

103-
### Solution 1
103+
### Solution 1: DFS + Mathematics
104+
105+
According to the problem description, we discuss the following cases:
106+
107+
When there is only one circle in `circles`:
108+
109+
1. If the starting point $(0, 0)$ is inside the circle (including the boundary), or the ending point $(\textit{xCorner}, \textit{yCorner})$ is inside the circle, then it is impossible to satisfy the condition of "not touching the circle".
110+
2. If the circle intersects with the left or top side of the rectangle and also intersects with the right or bottom side of the rectangle, then the circle will block the path from the bottom-left corner to the top-right corner of the rectangle, making it impossible to satisfy the condition of "not touching the circle".
111+
112+
When there are multiple circles in `circles`:
113+
114+
1. Similar to the above case, if the starting point or ending point is inside a circle, it is impossible to satisfy the condition of "not touching the circle".
115+
2. If there are multiple circles, they may intersect within the rectangle, forming a larger obstacle area. As long as this obstacle area intersects with the left or top side of the rectangle and also intersects with the right or bottom side of the rectangle, it is impossible to satisfy the condition of "not touching the circle". If the intersecting area is not inside the rectangle, it cannot be merged because the intersecting area cannot block the path inside the rectangle. Additionally, if part of the intersecting area is inside the rectangle and part is outside, these circles can be used as starting or ending points and can be merged or not. We only need to choose one of the intersecting points. If this point is inside the rectangle, we can merge these circles.
116+
117+
Based on the above analysis, we traverse all circles. For the current circle, if the starting point or ending point is inside the circle, we directly return `false`. Otherwise, if this point has not been visited and the circle intersects with the left or top side of the rectangle, we start a depth-first search (DFS) from this circle. During the search, if we find a circle that intersects with the right or bottom side of the rectangle, it means the obstacle area formed by the circles blocks the path from the bottom-left corner to the top-right corner of the rectangle, and we return `false`.
118+
119+
We define $\textit{dfs}(i)$ to represent starting a DFS from the $i$-th circle. If we find a circle that intersects with the right or bottom side of the rectangle, we return `true`; otherwise, we return `false`.
120+
121+
The execution process of the function $\textit{dfs}(i)$ is as follows:
122+
123+
1. If the current circle intersects with the right or bottom side of the rectangle, return `true`;
124+
2. Otherwise, mark the current circle as visited;
125+
3. Next, traverse all other circles. If circle $j$ has not been visited, and circle $i$ intersects with circle $j$, and one of the intersection points of these two circles is inside the rectangle, continue the DFS from circle $j$. If we find a circle that intersects with the right or bottom side of the rectangle, return `true`;
126+
4. If no such circle is found, return `false`.
127+
128+
In the above process, we need to determine whether two circles $O_1 = (x_1, y_1, r_1)$ and $O_2 = (x_2, y_2, r_2)$ intersect. If the distance between the centers of the two circles does not exceed the sum of their radii, i.e., $(x_1 - x_2)^2 + (y_1 - y_2)^2 \le (r_1 + r_2)^2$, then they intersect.
129+
130+
We also need to find an intersection point of the two circles. We take a point $A = (x, y)$ such that $\frac{O_1 A}{O_1 O_2} = \frac{r_1}{r_1 + r_2}$. If the two circles intersect, point $A$ must be in the intersection. In this case, $\frac{x - x_1}{x_2 - x_1} = \frac{r_1}{r_1 + r_2}$, solving for $x = \frac{x_1 r_2 + x_2 r_1}{r_1 + r_2}$. Similarly, $y = \frac{y_1 r_2 + y_2 r_1}{r_1 + r_2}$. As long as this point is inside the rectangle, we can continue the DFS, satisfying:
131+
132+
$$
133+
\begin{cases}
134+
x_1 r_2 + x_2 r_1 < (r_1 + r_2) \times \textit{xCorner} \\
135+
y_1 r_2 + y_2 r_1 < (r_1 + r_2) \times \textit{yCorner}
136+
\end{cases}
137+
$$
138+
139+
The time complexity is $O(n^2)$, and the space complexity is $O(n)$. Here, $n$ is the number of circles.
104140

105141
<!-- tabs:start -->
106142

@@ -414,6 +450,96 @@ function canReachCorner(xCorner: number, yCorner: number, circles: number[][]):
414450
}
415451
```
416452

453+
#### Rust
454+
455+
```rust
456+
impl Solution {
457+
pub fn can_reach_corner(x_corner: i32, y_corner: i32, circles: Vec<Vec<i32>>) -> bool {
458+
let n = circles.len();
459+
let mut vis = vec![false; n];
460+
461+
let in_circle = |x: i64, y: i64, cx: i64, cy: i64, r: i64| -> bool {
462+
(x - cx) * (x - cx) + (y - cy) * (y - cy) <= r * r
463+
};
464+
465+
let cross_left_top = |cx: i64, cy: i64, r: i64| -> bool {
466+
let a = cx.abs() <= r && (cy >= 0 && cy <= y_corner as i64);
467+
let b = (cy - y_corner as i64).abs() <= r && (cx >= 0 && cx <= x_corner as i64);
468+
a || b
469+
};
470+
471+
let cross_right_bottom = |cx: i64, cy: i64, r: i64| -> bool {
472+
let a = (cx - x_corner as i64).abs() <= r && (cy >= 0 && cy <= y_corner as i64);
473+
let b = cy.abs() <= r && (cx >= 0 && cx <= x_corner as i64);
474+
a || b
475+
};
476+
fn dfs(
477+
circles: &Vec<Vec<i32>>,
478+
vis: &mut Vec<bool>,
479+
i: usize,
480+
x_corner: i32,
481+
y_corner: i32,
482+
cross_right_bottom: &dyn Fn(i64, i64, i64) -> bool,
483+
) -> bool {
484+
let c = &circles[i];
485+
let (x1, y1, r1) = (c[0] as i64, c[1] as i64, c[2] as i64);
486+
487+
if cross_right_bottom(x1, y1, r1) {
488+
return true;
489+
}
490+
491+
vis[i] = true;
492+
493+
for j in 0..circles.len() {
494+
if vis[j] {
495+
continue;
496+
}
497+
498+
let c2 = &circles[j];
499+
let (x2, y2, r2) = (c2[0] as i64, c2[1] as i64, c2[2] as i64);
500+
501+
if (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) > (r1 + r2) * (r1 + r2) {
502+
continue;
503+
}
504+
505+
if x1 * r2 + x2 * r1 < (r1 + r2) * x_corner as i64
506+
&& y1 * r2 + y2 * r1 < (r1 + r2) * y_corner as i64
507+
&& dfs(circles, vis, j, x_corner, y_corner, cross_right_bottom)
508+
{
509+
return true;
510+
}
511+
}
512+
false
513+
}
514+
515+
for i in 0..n {
516+
let c = &circles[i];
517+
let (x, y, r) = (c[0] as i64, c[1] as i64, c[2] as i64);
518+
519+
if in_circle(0, 0, x, y, r) || in_circle(x_corner as i64, y_corner as i64, x, y, r) {
520+
return false;
521+
}
522+
523+
if !vis[i]
524+
&& cross_left_top(x, y, r)
525+
&& dfs(
526+
&circles,
527+
&mut vis,
528+
i,
529+
x_corner,
530+
y_corner,
531+
&cross_right_bottom,
532+
)
533+
{
534+
return false;
535+
}
536+
}
537+
538+
true
539+
}
540+
}
541+
```
542+
417543
<!-- tabs:end -->
418544

419545
<!-- solution:end -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
impl Solution {
2+
pub fn can_reach_corner(x_corner: i32, y_corner: i32, circles: Vec<Vec<i32>>) -> bool {
3+
let n = circles.len();
4+
let mut vis = vec![false; n];
5+
6+
let in_circle = |x: i64, y: i64, cx: i64, cy: i64, r: i64| -> bool {
7+
(x - cx) * (x - cx) + (y - cy) * (y - cy) <= r * r
8+
};
9+
10+
let cross_left_top = |cx: i64, cy: i64, r: i64| -> bool {
11+
let a = cx.abs() <= r && (cy >= 0 && cy <= y_corner as i64);
12+
let b = (cy - y_corner as i64).abs() <= r && (cx >= 0 && cx <= x_corner as i64);
13+
a || b
14+
};
15+
16+
let cross_right_bottom = |cx: i64, cy: i64, r: i64| -> bool {
17+
let a = (cx - x_corner as i64).abs() <= r && (cy >= 0 && cy <= y_corner as i64);
18+
let b = cy.abs() <= r && (cx >= 0 && cx <= x_corner as i64);
19+
a || b
20+
};
21+
fn dfs(
22+
circles: &Vec<Vec<i32>>,
23+
vis: &mut Vec<bool>,
24+
i: usize,
25+
x_corner: i32,
26+
y_corner: i32,
27+
cross_right_bottom: &dyn Fn(i64, i64, i64) -> bool,
28+
) -> bool {
29+
let c = &circles[i];
30+
let (x1, y1, r1) = (c[0] as i64, c[1] as i64, c[2] as i64);
31+
32+
if cross_right_bottom(x1, y1, r1) {
33+
return true;
34+
}
35+
36+
vis[i] = true;
37+
38+
for j in 0..circles.len() {
39+
if vis[j] {
40+
continue;
41+
}
42+
43+
let c2 = &circles[j];
44+
let (x2, y2, r2) = (c2[0] as i64, c2[1] as i64, c2[2] as i64);
45+
46+
if (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) > (r1 + r2) * (r1 + r2) {
47+
continue;
48+
}
49+
50+
if x1 * r2 + x2 * r1 < (r1 + r2) * x_corner as i64
51+
&& y1 * r2 + y2 * r1 < (r1 + r2) * y_corner as i64
52+
&& dfs(circles, vis, j, x_corner, y_corner, cross_right_bottom)
53+
{
54+
return true;
55+
}
56+
}
57+
false
58+
}
59+
60+
for i in 0..n {
61+
let c = &circles[i];
62+
let (x, y, r) = (c[0] as i64, c[1] as i64, c[2] as i64);
63+
64+
if in_circle(0, 0, x, y, r) || in_circle(x_corner as i64, y_corner as i64, x, y, r) {
65+
return false;
66+
}
67+
68+
if !vis[i]
69+
&& cross_left_top(x, y, r)
70+
&& dfs(
71+
&circles,
72+
&mut vis,
73+
i,
74+
x_corner,
75+
y_corner,
76+
&cross_right_bottom,
77+
)
78+
{
79+
return false;
80+
}
81+
}
82+
83+
true
84+
}
85+
}
Loading

0 commit comments

Comments
 (0)