[Leetcode解題] 3464. Maximize the Distance Between Points on a Square
26 April 2026
medium
binary-search
math
題目
3464. Maximize the Distance Between Points on a Square
給定一個邊長為 side 的正方形,其四個頂點分別為 (0, 0), (0, side), (side, 0) 和 (side, side)。
你還會得到一個位於正方形邊緣上的點的列表 points,以及一個整數 k。
你的目標是從這組點中選擇恰好 k 個點,使得這 k 個點中任意兩個點之間的最短曼哈頓距離(Manhattan distance)最大化。
請回傳此最大化的最短距離。
解題思路
這是一個典型的「最大化最小值」問題,通常可以使用「對答案進行二分搜尋」來解決。
- 展開正方形邊界為一維直線:
為了方便表示在邊緣上的位置和計算點與點之間的直線距離,我們可以將正方形的周界展平成一條長度為
4 * side的直線區間[0, 4 * side)。 我們定義一個將二維座標轉換為一維純量值的方法:- 下邊界 (
y=0):距離起點的值為x - 右邊界 (
x=side):值為side + y - 上邊界 (
y=side):值為3 * side - x - 左邊界 (
x=0):值為4 * side - y
- 下邊界 (
-
對轉換後的點排序: 將所有點轉換為一維的所在位置並從小到大排序(時間複雜度為 $O(n \log n)$),以方便後續我們用貪婪法 (Greedy) 和二分搜尋來判定解的可行性。
-
二分搜尋最短距離 (Binary Search on Answer): 我們在可能的距離範圍
0到side之間進行二分搜尋。對於每個距離候選值mid,我們使用check(d)函數檢查是否可以順利挑選出k個點,且任兩點距離長度最少為mid。 - 驗證條件 (
check函數):- 由於點分佈在環形的邊緣上,我們嘗試以每個有給出的點
pos[i]作為候選的「第一顆點」,模擬貪婪向後地去挑選剩下的點。 - 因為其各點的位置等價在一維陣列上且已排序,我們可以使用
bisect.bisect_left以 $O(\log n)$ 的時間快速尋找「與當前點距離大於等於d」的下一個點所在的索引。 - 當能夠順利挑滿
k個點時,我們還需要確認最後一個選出的點與最開始第一顆點的距離。因為這是一個長度為4 * side的環,頭尾銜接處同樣必須滿足距離 $\ge d$ 的條件 (4 * side - (last_pos - start_pos) >= d)。 - 若符合則此距離
d是合法的,提早回傳True即可。
- 由於點分佈在環形的邊緣上,我們嘗試以每個有給出的點
- 根據每次檢查驗證的結果去調整二分搜尋的上下範圍
low與high,並更新合法的距離記錄,直到二分搜尋結束。
Python 實作
import bisect
class Solution:
def maxDistance(self, side: int, points: list[list[int]], k: int) -> int:
def get_dist(x, y):
if y == 0: return x
if x == side: return side + y
if y == side: return 3 * side - x
if x == 0: return 4 * side - y
return 0
pos = sorted([get_dist(x, y) for x, y in points])
n = len(pos)
def check(d):
for i in range(n): # Any optimization?
count = 1
last_pos = pos[i]
start_pos = pos[i]
curr_idx = i
for _ in range(k - 1):
target = last_pos + d
idx = bisect.bisect_left(pos, target)
if idx == n:
count = -1
break
last_pos = pos[idx]
count += 1
if count == k and (4 * side - (last_pos - start_pos)) >= d:
return True
return False
low, high = 0, side
ans = 0
while low <= high:
mid = (low + high) // 2
if check(mid):
ans = mid
low = mid + 1
else:
high = mid - 1
return ans
時間複雜度
- 將所有的點展開一維化並且按照順序排序,需要時間 $O(n \log n)$。
- 檢查合法條件的
check函數最壞情況下可能進入 $O(n \cdot k \log n)$ 次計算。外部二分搜尋則需執行 $O(\log(\text{side}))$ 次。 - 整體的總時間複雜度大約為 $O(n \log n + \log(\text{side}) \cdot n \cdot k \log n)$。
- 空間複雜度:需要長度為 $n$ 的
pos陣列來儲存處理過的位置,空間耗費為 $O(n)$。