LeetCode 849. 到最近的人的最大距离
题目描述



题意分析
1表示有人,0表示空位。选择一个空位,使它与最近已有人的下标距离尽可能大,返回这个距离。题目保证至少有一个人和一个空位。
解法:一次扫描统计 0 段长度
核心思路
[!blue]
同一段连续空位中的任意座位,最近的人只可能是紧邻这段的左边或右边的人,更远的人不需要考虑。因此可以把空位划成连续段,分别求出每段的最佳距离,再取最大值。
对中间空段,设长度为
len,两侧人的下标距离是len + 1。坐在其中任何位置,到两边的距离之和都等于len + 1,较小的一个不可能超过floor((len + 1) / 2);坐在中间位置就能达到这个上界,所以这就是该段的最优值。贴着数组端点的空段只有一侧有人,越往外侧坐距离越大。选择最左端或最右端,最近距离正好等于空段长度
len,不能再除以 2。扫描时用半开区间
[i, j)表示一整段空位,长度为j - i。i == 0或j == n就是端点段,否则是中间段。每段计算后令i = j,不再重新扫描已处理的空位。
解题步骤
- 遇到有人座位就跳过。
- 从空位起点向右找到整段结束位置。
- 若空段贴着任一端点,候选距离取段长;否则取
(段长 + 1) / 2的整数除法结果。- 更新全局最大距离并继续下一段。
代码实现
class Solution {
public int maxDistToClosest(int[] seats) {
int n = seats.length;
int answer = 0;
int i = 0;
while (i < n) {
if (seats[i] == 1) {
i++;
continue;
}
int j = i;
while (j < n && seats[j] == 0) {
j++;
}
// 连续空位段采用左闭右开区间,长度为结束位置减起点。
int len = j - i;
// 端点空段只有一侧有人,最外侧可获得整段长度的距离。
if (i == 0 || j == n) {
answer = Math.max(answer, len);
} else {
answer = Math.max(answer, (len + 1) / 2);
}
i = j;
}
return answer;
}
}
func maxDistToClosest(seats []int) int {
n := len(seats)
answer := 0
i := 0
for i < n {
if seats[i] == 1 {
i++
continue
}
j := i
for j < n && seats[j] == 0 {
j++
}
// 连续空位段采用左闭右开区间,长度为结束位置减起点。
length := j - i
// 端点空段只有一侧有人,最外侧可获得整段长度的距离。
if i == 0 || j == n {
if length > answer {
answer = length
}
} else {
cand := (length + 1) / 2
if cand > answer {
answer = cand
}
}
i = j
}
return answer
}
复杂度分析
- 时间复杂度:$O(n)$,逐段扫描且不回退。
- 空间复杂度:$O(1)$。
关键点总结
[!green]
- 端点段与中间段受到的两侧约束不同。
- 空段长度和两个人的下标差相差一。
- 答案是最近距离的最大值,不是座位下标。
易错点总结
[!yellow]
- 端点空段也除以二:低估靠最外侧的位置。
- 中间段直接用 len/2:空位段长比两侧人的距离少 1,会低估部分奇数长度空段的答案。
- 遗漏右端空段:最后一个人之后也可能有最佳空位。
- 探测段末不判断数组边界:末尾连续空位会导致越界。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 475. 供暖器 | 中等 | 同样取到最近已有位置的距离,原题保证每所房子被供暖,本题在空位中选择最远离已坐人的位置。 |
| 821. 字符的最短距离 | 简单 | 原题返回所有位置到目标的最短距离,本题只在空位中取这些距离的最大值。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!