Skip to content
Open
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
130 changes: 130 additions & 0 deletions problems/1401-circle-and-rectangle-overlapping/analysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# 1401. Circle and Rectangle Overlapping

[LeetCode Link](https://leetcode.com/problems/circle-and-rectangle-overlapping/)

Difficulty: Medium
Topics: Math, Geometry
Acceptance Rate: 56.2%

## Hints

### Hint 1

This is tagged Medium, but the hard part is not the algorithm — it is asking the
right question. There is no data structure to pick and no loop to write. Resist
the urge to enumerate candidate points (corners, edge midpoints, lattice points
inside the rectangle): any such enumeration either misses cases or needs a proof
you will not want to write in an interview. Instead, restate the problem as a
distance question about *one* well-chosen point.

### Hint 2

Two shapes overlap exactly when the **shortest distance** between the circle's
center and the rectangle is at most `radius`. So the whole problem reduces to:
given a point and an axis-aligned rectangle, which point of the rectangle is
closest to that point? Because the rectangle is axis-aligned, the x and y
dimensions are completely independent — you can solve each axis separately and
then combine.

### Hint 3

On the x-axis alone, the closest x-coordinate inside `[x1, x2]` to `xCenter` is
just `xCenter` **clamped** into that interval: `min(max(xCenter, x1), x2)`. Do
the same for y. The resulting point `(cx, cy)` is the closest point of the whole
rectangle to the center — and it is automatically correct whether the center sits
inside the rectangle, beside an edge, or diagonally past a corner. Then answer
`(xCenter-cx)² + (yCenter-cy)² <= radius²`, comparing squares so you never touch
floating point.

## Approach

The key reframing: "do the circle and rectangle share a point?" is equivalent to
"is the closest point of the rectangle to the circle's center within `radius` of
that center?"

Why the equivalence holds: the rectangle is a closed convex set. Let `P` be the
point of the rectangle minimizing distance to the center `C`.

- If `dist(C, P) <= radius`, then `P` lies in the disk and in the rectangle, so
they overlap.
- If `dist(C, P) > radius`, then *every* point of the rectangle is farther than
`radius` from `C` (since `P` is the minimizer), so no point of the rectangle is
in the disk and they cannot overlap.

Finding `P` is where the axis-aligned assumption pays off. The rectangle is the
Cartesian product `[x1, x2] × [y1, y2]`, so squared distance separates:

```
dist²(C, (x, y)) = (xCenter - x)² + (yCenter - y)²
```

The two terms depend on different variables and both are non-negative, so we can
minimize each independently. Minimizing `(xCenter - x)²` over `x ∈ [x1, x2]` is
the classic clamp:

```
cx = clamp(xCenter, x1, x2) = min(max(xCenter, x1), x2)
```

and likewise `cy = clamp(yCenter, y1, y2)`. The clamp quietly handles all nine
relative positions of the center at once:

- center's x is inside `[x1, x2]` → `cx = xCenter`, that term contributes 0
- center is left of the rectangle → `cx = x1`
- center is right of the rectangle → `cx = x2`

Combined over both axes, an interior center gives `P = C` and distance 0; a
center beside an edge gives the perpendicular foot on that edge; a center
diagonally outside gives the nearest corner. No case analysis needed in the code.

Finally, compare squared distances instead of distances:

```
(xCenter - cx)² + (yCenter - cy)² <= radius²
```

Squaring is monotone on non-negative numbers, so the comparison is unchanged, and
we stay in exact integer arithmetic — no `math.Sqrt`, no epsilon tuning. With
coordinates bounded by 10⁴, each difference is at most 2·10⁴, so the sum is at
most 8·10⁸, comfortably inside `int`.

Walking through Example 2 (`radius = 1`, center `(1, 1)`, rectangle
`x1=1, y1=-3, x2=2, y2=-1`): `cx = clamp(1, 1, 2) = 1` and
`cy = clamp(1, -3, -1) = -1`, so the closest point is `(1, -1)` with squared
distance `0 + 4 = 4 > 1 = radius²` → `false`. The center is horizontally aligned
with the rectangle but two units above its top edge.

## Complexity Analysis

Time Complexity: O(1) — a fixed number of comparisons and multiplications, with
no loops and no dependence on coordinate magnitudes.
Space Complexity: O(1) — only a few integer temporaries.

## Edge Cases

- **Center inside the rectangle.** Both clamps return the center itself, giving
squared distance 0, which is `<= radius²` for any `radius >= 1`. Correctly
`true`. A corner-only or edge-only check would get this wrong.
- **Tangency (touching at exactly one point).** The problem counts a shared point
as overlapping, so the comparison must be `<=`, not `<`. Example 1 is exactly
this case: the circle touches the rectangle only at `(1, 0)`. Using `<` fails
the very first example.
- **Center diagonally past a corner.** E.g. `radius = 1`, center `(0, 0)`,
rectangle `(1, 1, 2, 2)`: the nearest point is the corner `(1, 1)` at squared
distance 2 > 1 → `false`. The circle crosses both the vertical line `x = 1` and
the horizontal line `y = 1`, so any approach that tests the two axes in
isolation ("does the x-range overlap AND the y-range overlap?") wrongly reports
`true`. Both axes must be combined in a single distance.
- **Center aligned with an edge but outside.** Example 2 above: the x-projection
overlaps the rectangle while the y-distance decides the answer. The clamp gives
the perpendicular foot on the edge, not a corner.
- **Rectangle entirely inside the circle.** The clamped point is the rectangle
corner/edge point nearest the center, which is *within* the circle, so the
check returns `true` — no separate containment test needed.
- **Extreme coordinates.** Center at `(-10⁴, -10⁴)` with the rectangle near
`(10⁴, 10⁴)` yields squared distance up to 8·10⁸. Fine for Go's `int`, but
worth noting if you port this to a 32-bit signed type where `radius² ` and the
sum still fit, yet a careless `dist⁴`-style manipulation would not.
- **Degenerate rectangles are impossible.** Constraints guarantee `x1 < x2` and
`y1 < y2`, so the rectangle always has positive area; the clamp would still be
correct for a degenerate point or segment anyway.
59 changes: 59 additions & 0 deletions problems/1401-circle-and-rectangle-overlapping/problem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
number: "1401"
frontend_id: "1401"
title: "Circle and Rectangle Overlapping"
slug: "circle-and-rectangle-overlapping"
difficulty: "Medium"
topics:
- "Math"
- "Geometry"
acceptance_rate: 5623.4
is_premium: false
created_at: "2026-09-19T04:50:22.341381+00:00"
fetched_at: "2026-09-19T04:50:22.341381+00:00"
link: "https://leetcode.com/problems/circle-and-rectangle-overlapping/"
date: "2026-09-19"
---

# 1401. Circle and Rectangle Overlapping

You are given a circle represented as `(radius, xCenter, yCenter)` and an axis-aligned rectangle represented as `(x1, y1, x2, y2)`, where `(x1, y1)` are the coordinates of the bottom-left corner, and `(x2, y2)` are the coordinates of the top-right corner of the rectangle.

Return `true` _if the circle and rectangle are overlapped otherwise return_`false`. In other words, check if there is **any** point `(xi, yi)` that belongs to the circle and the rectangle at the same time.



**Example 1:**

![](https://assets.leetcode.com/uploads/2020/02/20/sample_4_1728.png)


**Input:** radius = 1, xCenter = 0, yCenter = 0, x1 = 1, y1 = -1, x2 = 3, y2 = 1
**Output:** true
**Explanation:** Circle and rectangle share the point (1,0).


**Example 2:**


**Input:** radius = 1, xCenter = 1, yCenter = 1, x1 = 1, y1 = -3, x2 = 2, y2 = -1
**Output:** false


**Example 3:**

![](https://assets.leetcode.com/uploads/2020/02/20/sample_2_1728.png)


**Input:** radius = 1, xCenter = 0, yCenter = 0, x1 = -1, y1 = 0, x2 = 0, y2 = 1
**Output:** true




**Constraints:**

* `1 <= radius <= 2000`
* `-104 <= xCenter, yCenter <= 104`
* `-104 <= x1 < x2 <= 104`
* `-104 <= y1 < y2 <= 104`
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

// 1401. Circle and Rectangle Overlapping
//
// The circle and the axis-aligned rectangle overlap exactly when the point of
// the rectangle closest to the circle's center lies within radius of it.
// Because the rectangle is [x1,x2] x [y1,y2], the closest point is found by
// clamping the center's coordinates into each interval independently. Comparing
// squared distances keeps everything in exact integer arithmetic.
//
// Time: O(1), Space: O(1).

func checkOverlap(radius int, xCenter int, yCenter int, x1 int, y1 int, x2 int, y2 int) bool {
// Closest point of the rectangle to the circle's center.
cx := clampInt(xCenter, x1, x2)
cy := clampInt(yCenter, y1, y2)

dx := xCenter - cx
dy := yCenter - cy

// "<=" because sharing a single boundary point counts as overlapping.
return dx*dx+dy*dy <= radius*radius
}

// clampInt returns v restricted to the closed interval [lo, hi].
func clampInt(v, lo, hi int) int {
if v < lo {
return lo
}
if v > hi {
return hi
}
return v
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package main

import "testing"

func TestSolution(t *testing.T) {
tests := []struct {
name string
radius int
xCenter int
yCenter int
x1 int
y1 int
x2 int
y2 int
expected bool
}{
{
name: "example 1: circle touches rectangle at the single point (1,0)",
radius: 1,
xCenter: 0, yCenter: 0,
x1: 1, y1: -1, x2: 3, y2: 1,
expected: true,
},
{
name: "example 2: center aligned horizontally but rectangle sits below",
radius: 1,
xCenter: 1, yCenter: 1,
x1: 1, y1: -3, x2: 2, y2: -1,
expected: false,
},
{
name: "example 3: rectangle corner coincides with the circle center",
radius: 1,
xCenter: 0, yCenter: 0,
x1: -1, y1: 0, x2: 0, y2: 1,
expected: true,
},
{
name: "edge case: center strictly inside the rectangle",
radius: 1,
xCenter: 5, yCenter: 5,
x1: 0, y1: 0, x2: 10, y2: 10,
expected: true,
},
{
name: "edge case: rectangle entirely contained in the circle",
radius: 2000,
xCenter: 0, yCenter: 0,
x1: -1, y1: -1, x2: 1, y2: 1,
expected: true,
},
{
name: "edge case: diagonally past a corner, both axis ranges overlap the circle",
radius: 1,
xCenter: 0, yCenter: 0,
x1: 1, y1: 1, x2: 2, y2: 2,
expected: false,
},
{
name: "edge case: exact tangency at a corner (3,4) with radius 5",
radius: 5,
xCenter: 0, yCenter: 0,
x1: 3, y1: 4, x2: 10, y2: 10,
expected: true,
},
{
name: "edge case: exact tangency against a vertical edge",
radius: 2,
xCenter: 0, yCenter: 0,
x1: 2, y1: -5, x2: 5, y2: 5,
expected: true,
},
{
name: "edge case: vertical edge one unit too far away",
radius: 2,
xCenter: 0, yCenter: 0,
x1: 3, y1: -5, x2: 5, y2: 5,
expected: false,
},
{
name: "edge case: extreme opposite corners of the coordinate range",
radius: 2000,
xCenter: -10000, yCenter: -10000,
x1: 9999, y1: 9999, x2: 10000, y2: 10000,
expected: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := checkOverlap(tt.radius, tt.xCenter, tt.yCenter, tt.x1, tt.y1, tt.x2, tt.y2)
if got != tt.expected {
t.Errorf("checkOverlap(%d, %d, %d, %d, %d, %d, %d) = %v, want %v",
tt.radius, tt.xCenter, tt.yCenter, tt.x1, tt.y1, tt.x2, tt.y2, got, tt.expected)
}
})
}
}