@@ -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