Skip to content

Commit 5474f02

Browse files
authored
feat: add solutions for lc No.3464 (#5177)
1 parent ee5b9bd commit 5474f02

7 files changed

Lines changed: 845 additions & 8 deletions

File tree

solution/3400-3499/3464.Maximize the Distance Between Points on a Square/README.md

Lines changed: 290 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,32 +100,318 @@ tags:
100100

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

103-
### 方法一
103+
### 方法一:二分答案 + 坐标映射 + 贪心
104+
105+
由于题目要求最大化最小距离,我们可以通过二分答案的方式来寻找最优解。
106+
107+
首先,为了简化逻辑,我们将正方形边界上的二维坐标 $(x, y)$ 映射到一维数轴 $[0, 4 \times \text{side})$ 上。映射规则如下:
108+
109+
- 若 $x = 0$,映射值为 $y$;
110+
- 若 $y = \text{side}$,映射值为 $\text{side} + x$;
111+
- 若 $x = \text{side}$,映射值为 $3 \times \text{side} - y$;
112+
- 否则,映射值为 $4 \times \text{side} - x$。
113+
114+
映射后,将所有坐标点排序得到数组 $\textit{nums}$。由于是在正方形周长上选取点,这本质上是一个环形问题。
115+
116+
在二分过程中,对于给定的最小距离 $\textit{lo}$,我们通过 $\textit{check}$ 函数验证其可行性:
117+
118+
- 遍历 $\textit{nums}$ 中的每个点作为第一个点 $\textit{start}$。
119+
- 限制选点范围的终点为 $\textit{end} = \textit{start} + 4 \times \text{side} - \textit{lo}$,确保选出的最后一个点回到起点 $\textit{start}$ 的环绕距离也至少为 $\textit{lo}$。
120+
- 随后贪心地进行 $k-1$ 次跳转,每次利用二分查找快速定位下一个距离当前位置至少为 $\textit{lo}$ 的点。
121+
- 如果能在满足 $\textit{end}$ 限制的情况下选够 $k$ 个点,则该距离 $\textit{lo}$ 可行。
122+
123+
时间复杂度 $O(n \log (\text{side}) \cdot n \log n)$,空间复杂度 $O(n)$。其中 $n$ 为点集 $\textit{points}$ 的长度。
104124

105125
<!-- tabs:start -->
106126

107127
#### Python3
108128

109129
```python
110-
130+
class Solution:
131+
def maxDistance(self, side: int, points: List[List[int]], k: int) -> int:
132+
nums = []
133+
for x, y in points:
134+
if x == 0:
135+
nums.append(y)
136+
elif y == side:
137+
nums.append(side + x)
138+
elif x == side:
139+
nums.append(side * 3 - y)
140+
else:
141+
nums.append(side * 4 - x)
142+
nums.sort()
143+
144+
def check(lo: int) -> bool:
145+
for start in nums:
146+
end = start + side * 4 - lo
147+
cur = start
148+
ok = True
149+
for _ in range(k - 1):
150+
j = bisect_left(nums, cur + lo)
151+
if j == len(nums) or nums[j] > end:
152+
ok = False
153+
break
154+
cur = nums[j]
155+
if ok:
156+
return True
157+
return False
158+
159+
l, r = 1, side
160+
while l < r:
161+
mid = (l + r + 1) >> 1
162+
if check(mid):
163+
l = mid
164+
else:
165+
r = mid - 1
166+
return l
111167
```
112168

113169
#### Java
114170

115171
```java
116-
172+
class Solution {
173+
private int side;
174+
private long[] nums;
175+
private int k;
176+
177+
public int maxDistance(int side, int[][] points, int k) {
178+
this.side = side;
179+
this.k = k;
180+
int n = points.length;
181+
this.nums = new long[n];
182+
for (int i = 0; i < n; i++) {
183+
int x = points[i][0];
184+
int y = points[i][1];
185+
if (x == 0) {
186+
nums[i] = (long) y;
187+
} else if (y == side) {
188+
nums[i] = (long) side + x;
189+
} else if (x == side) {
190+
nums[i] = (long) side * 3 - y;
191+
} else {
192+
nums[i] = (long) side * 4 - x;
193+
}
194+
}
195+
Arrays.sort(nums);
196+
197+
int l = 1, r = side;
198+
while (l < r) {
199+
int mid = (l + r + 1) >> 1;
200+
if (check(mid)) {
201+
l = mid;
202+
} else {
203+
r = mid - 1;
204+
}
205+
}
206+
return l;
207+
}
208+
209+
private boolean check(int lo) {
210+
long total = (long) side * 4;
211+
for (int i = 0; i < nums.length; i++) {
212+
long start = nums[i];
213+
long end = start + total - lo;
214+
long cur = start;
215+
boolean ok = true;
216+
for (int j = 0; j < k - 1; j++) {
217+
long target = cur + lo;
218+
int idx = lowerBound(nums, target);
219+
if (idx == nums.length || nums[idx] > end) {
220+
ok = false;
221+
break;
222+
}
223+
cur = nums[idx];
224+
}
225+
if (ok) {
226+
return true;
227+
}
228+
}
229+
return false;
230+
}
231+
232+
private int lowerBound(long[] arr, long target) {
233+
int left = 0, right = arr.length;
234+
while (left < right) {
235+
int mid = (left + right) >>> 1;
236+
if (arr[mid] < target) {
237+
left = mid + 1;
238+
} else {
239+
right = mid;
240+
}
241+
}
242+
return left;
243+
}
244+
}
117245
```
118246

119247
#### C++
120248

121249
```cpp
122-
250+
class Solution {
251+
public:
252+
int maxDistance(int side, vector<vector<int>>& points, int k) {
253+
vector<long long> nums;
254+
for (auto& p : points) {
255+
int x = p[0];
256+
int y = p[1];
257+
if (x == 0) {
258+
nums.push_back((long long) y);
259+
} else if (y == side) {
260+
nums.push_back((long long) side + x);
261+
} else if (x == side) {
262+
nums.push_back((long long) side * 3 - y);
263+
} else {
264+
nums.push_back((long long) side * 4 - x);
265+
}
266+
}
267+
sort(nums.begin(), nums.end());
268+
269+
auto check = [&](int lo) -> bool {
270+
long long total = (long long) side * 4;
271+
for (long long start : nums) {
272+
long long end = start + total - lo;
273+
long long cur = start;
274+
bool ok = true;
275+
for (int i = 0; i < k - 1; ++i) {
276+
auto it = lower_bound(nums.begin(), nums.end(), cur + lo);
277+
if (it == nums.end() || *it > end) {
278+
ok = false;
279+
break;
280+
}
281+
cur = *it;
282+
}
283+
if (ok) {
284+
return true;
285+
}
286+
}
287+
return false;
288+
};
289+
290+
int l = 1, r = side;
291+
while (l < r) {
292+
int mid = (l + r + 1) >> 1;
293+
if (check(mid)) {
294+
l = mid;
295+
} else {
296+
r = mid - 1;
297+
}
298+
}
299+
return l;
300+
}
301+
};
123302
```
124303

125304
#### Go
126305

127306
```go
307+
func maxDistance(side int, points [][]int, k int) int {
308+
nums := make([]int64, 0, len(points))
309+
for _, p := range points {
310+
x, y := int64(p[0]), int64(p[1])
311+
s := int64(side)
312+
if x == 0 {
313+
nums = append(nums, y)
314+
} else if y == s {
315+
nums = append(nums, s+x)
316+
} else if x == s {
317+
nums = append(nums, s*3-y)
318+
} else {
319+
nums = append(nums, s*4-x)
320+
}
321+
}
322+
sort.Slice(nums, func(i, j int) bool {
323+
return nums[i] < nums[j]
324+
})
325+
326+
check := func(lo int) bool {
327+
total := int64(side) * 4
328+
l64 := int64(lo)
329+
for _, start := range nums {
330+
end := start + total - l64
331+
cur := start
332+
ok := true
333+
for i := 0; i < k-1; i++ {
334+
target := cur + l64
335+
idx := sort.Search(len(nums), func(i int) bool {
336+
return nums[i] >= target
337+
})
338+
if idx == len(nums) || nums[idx] > end {
339+
ok = false
340+
break
341+
}
342+
cur = nums[idx]
343+
}
344+
if ok {
345+
return true
346+
}
347+
}
348+
return false
349+
}
350+
351+
l, r := 1, side
352+
for l < r {
353+
mid := (l + r + 1) >> 1
354+
if check(mid) {
355+
l = mid
356+
} else {
357+
r = mid - 1
358+
}
359+
}
360+
return l
361+
}
362+
```
128363

364+
#### TypeScript
365+
366+
```ts
367+
function maxDistance(side: number, points: number[][], k: number): number {
368+
const nums: number[] = [];
369+
for (const [x, y] of points) {
370+
if (x === 0) {
371+
nums.push(y);
372+
} else if (y === side) {
373+
nums.push(side + x);
374+
} else if (x === side) {
375+
nums.push(side * 3 - y);
376+
} else {
377+
nums.push(side * 4 - x);
378+
}
379+
}
380+
nums.sort((a, b) => a - b);
381+
382+
const check = (lo: number): boolean => {
383+
const total = side * 4;
384+
for (const start of nums) {
385+
const end = start + total - lo;
386+
let cur = start;
387+
let ok = true;
388+
for (let i = 0; i < k - 1; i++) {
389+
const j = _.sortedIndex(nums, cur + lo);
390+
if (j === nums.length || nums[j] > end) {
391+
ok = false;
392+
break;
393+
}
394+
cur = nums[j];
395+
}
396+
if (ok) {
397+
return true;
398+
}
399+
}
400+
return false;
401+
};
402+
403+
let l = 1,
404+
r = side;
405+
while (l < r) {
406+
const mid = (l + r + 1) >> 1;
407+
if (check(mid)) {
408+
l = mid;
409+
} else {
410+
r = mid - 1;
411+
}
412+
}
413+
return l;
414+
}
129415
```
130416

131417
<!-- tabs:end -->

0 commit comments

Comments
 (0)