DoorDash 最近邻城市面试题 2026:同轴最近城市高分解法
DoorDash 最近邻城市面试题 2026 是近期高频题。
因此,本文给你一套可复述模板。
这是我们学员贡献的最新面经。
同时,这也是 2026年最新 面试经验。
此外,题目描述很长,规则很多。
但是,核心只有筛选与比较。
先筛同 x 或同 y 的城市。
然后,再做距离和字典序判断。
2026 面试流程深度复盘:DoorDash 最近邻城市面试题 2026
具体来说,开场先确认输入格式。
城市名通常唯一。
与此同时,查询次数可能很多。
你要主动问清空值返回规则。
因此,先给暴力解很重要。
每次查询都扫全部城市。
命中同轴候选后计算距离。
最后按 tie-break 更新答案。
此外,DoorDash 最近邻城市面试题 2026 常追问两轮优化。
第一轮是按 x 与 y 分组。
第二轮是组内排序加二分。
换句话说,你要主动指出瓶颈。
但是,面试官也看沟通质量。
你要边写边讲复杂度。
同时,要明确预处理代价。
此外,要解释为何查询是对数级。
总而言之,这题节奏是先稳后快。
先保正确,再做优化。
与此同时,主动补充边界用例。
这会明显提高通过率。
核心题目解析
因此,我们把 DoorDash 最近邻城市面试题 2026 拆成三层。
第一层是规则复述。
第二层是数据结构选择。
第三层是 tie-break 一次写对。
1) 题意与判定规则
具体来说,只比较同 x 或同 y 的点。
距离可写成 |dx| + |dy|。
因为同轴,所以是单轴差值。
如果没有候选,返回 NONE。
2) 暴力解法(先拿基础分)
因此,暴力法最直接。
对每个查询遍历全部城市。
满足同轴就尝试更新答案。
时间复杂度是 O(n*q)。
3) 优化解法(分组 + 排序 + 二分)
此外,优化法要建两个索引。
x -> 有序 y 键 是第一个。
y -> 有序 x 键 是第二个。
每个键下放名字有序集合。
查询时先走 x 索引。
然后,二分定位当前 y。
与此同时,只检查左邻和右邻。
若同键桶有他城,距离就是 0。
但是,最终比较要统一函数。
先比距离,再比名字。
这样可稳定处理平局。
因此,单次查询是 O(log n) 级。
总而言之,复杂度可这样陈述。
- 预处理:O(n log n)
- 单次查询:O(log n)
- 额外空间:O(n)
4) 逻辑流程图(可直接口述)
与此同时,你可以按下图讲流程。
flowchart TD
A[读取城市与坐标] --> B[按 x 分组并排序 y]
A --> C[按 y 分组并排序 x]
B --> D[收到查询城市]
C --> D
D --> E[二分定位邻近坐标桶]
E --> F[生成 x 轴候选与 y 轴候选]
F --> G[先比较距离]
G --> H[距离相同比字典序]
H --> I[输出城市名或 NONE]
5) Java 参考实现(含注释)
此外,下面代码覆盖完整规则。
import java.util.*;
public class NearestCitySolver {
private static class City {
String name;
int x;
int y;
City(String name, int x, int y) {
this.name = name;
this.x = x;
this.y = y;
}
}
private static class AxisIndex {
List<Integer> keys; // 排序后的可变坐标
Map<Integer, TreeSet<String>> coordToNames; // 坐标 -> 城市名有序集
AxisIndex(List<Integer> keys, Map<Integer, TreeSet<String>> coordToNames) {
this.keys = keys;
this.coordToNames = coordToNames;
}
}
private static class Candidate {
String name;
long dist;
Candidate(String name, long dist) {
this.name = name;
this.dist = dist;
}
}
private final Map<String, City> nameToCity = new HashMap<>();
private final Map<Integer, AxisIndex> byX;
private final Map<Integer, AxisIndex> byY;
public NearestCitySolver(String[] names, int[] xs, int[] ys) {
if (names.length != xs.length || xs.length != ys.length) {
throw new IllegalArgumentException("Input length mismatch.");
}
Map<Integer, Map<Integer, TreeSet<String>>> xTmp = new HashMap<>();
Map<Integer, Map<Integer, TreeSet<String>>> yTmp = new HashMap<>();
for (int i = 0; i < names.length; i++) {
City city = new City(names[i], xs[i], ys[i]);
if (nameToCity.putIfAbsent(city.name, city) != null) {
throw new IllegalArgumentException("Duplicate city name: " + city.name);
}
xTmp.computeIfAbsent(city.x, k -> new HashMap<>())
.computeIfAbsent(city.y, k -> new TreeSet<>())
.add(city.name);
yTmp.computeIfAbsent(city.y, k -> new HashMap<>())
.computeIfAbsent(city.x, k -> new TreeSet<>())
.add(city.name);
}
this.byX = buildIndex(xTmp);
this.byY = buildIndex(yTmp);
}
private Map<Integer, AxisIndex> buildIndex(
Map<Integer, Map<Integer, TreeSet<String>>> raw) {
Map<Integer, AxisIndex> out = new HashMap<>();
for (Map.Entry<Integer, Map<Integer, TreeSet<String>>> entry : raw.entrySet()) {
int fixed = entry.getKey();
Map<Integer, TreeSet<String>> inner = entry.getValue();
List<Integer> keys = new ArrayList<>(inner.keySet());
Collections.sort(keys);
Map<Integer, TreeSet<String>> buckets = new HashMap<>();
for (Map.Entry<Integer, TreeSet<String>> e : inner.entrySet()) {
buckets.put(e.getKey(), new TreeSet<>(e.getValue()));
}
out.put(fixed, new AxisIndex(keys, buckets));
}
return out;
}
public String query(String cityName) {
City city = nameToCity.get(cityName);
if (city == null) return "NONE";
Candidate best = null;
best = better(best, queryOnAxis(byX.get(city.x), city.y, city.name));
best = better(best, queryOnAxis(byY.get(city.y), city.x, city.name));
return best == null ? "NONE" : best.name;
}
public List<String> batchQuery(String[] queries) {
List<String> ans = new ArrayList<>(queries.length);
for (String q : queries) {
ans.add(query(q));
}
return ans;
}
private Candidate queryOnAxis(AxisIndex index, int coord, String selfName) {
if (index == null || index.keys.isEmpty()) return null;
List<Integer> keys = index.keys;
int bs = Collections.binarySearch(keys, coord);
Candidate best = null;
int left;
int right;
if (bs >= 0) {
best = better(best, fromSameCoord(index.coordToNames.get(coord), selfName));
left = bs - 1;
right = bs + 1;
} else {
int insertPos = -bs - 1;
left = insertPos - 1;
right = insertPos;
}
if (left >= 0) {
int c = keys.get(left);
String name = index.coordToNames.get(c).first();
best = better(best, new Candidate(name, Math.abs((long) coord - c)));
}
if (right < keys.size()) {
int c = keys.get(right);
String name = index.coordToNames.get(c).first();
best = better(best, new Candidate(name, Math.abs((long) coord - c)));
}
return best;
}
private Candidate fromSameCoord(TreeSet<String> names, String selfName) {
if (names == null) return null;
if (names.size() == 1 && names.contains(selfName)) return null;
String pick = names.first();
if (pick.equals(selfName)) {
pick = names.higher(selfName);
}
if (pick == null) return null;
return new Candidate(pick, 0L);
}
private Candidate better(Candidate a, Candidate b) {
if (a == null) return b;
if (b == null) return a;
if (a.dist != b.dist) return a.dist < b.dist ? a : b;
return a.name.compareTo(b.name) <= 0 ? a : b;
}
}
6) 易错边界清单
因此,面试前要把坑位过一遍。
- 查询城市不存在。
- 同轴只有自己一座城。
- 两侧等距且名字需比较。
- 同坐标多城市且要排除自己。
- 坐标可能为负数。
- 输入长度不一致。
- 城市名重复。
专家备考策略与高频考点:DoorDash 最近邻城市面试题 2026
与此同时,DoorDash 最近邻城市面试题 2026 的得分点很固定。
因此,你要按评分维度准备。
此外,先练口述,再练编码。
最后做一次 45 分钟限时模拟。
具体来说,核心考点如下。
- 约束建模:只看同 x 或同 y。
- 方案对比:先暴力,再优化。
- 二分定位:能解释邻近桶逻辑。
- 规则落地:tie-break 一致且稳定。
- 复杂度:预处理与查询分开讲。
- 工程能力:Java 细节与 bug 修复。
此外,BQ 常和技术题连问。
STAR 应对策略
1. Situation:先说题目长且规则多。
2. Task:再说目标是稳准快实现。
3. Action:然后给建模、优化、验证。
4. Result:最后给复杂度和通过结果。
总结与行动号召(CTA)
总而言之,DoorDash 最近邻城市面试题 2026 并不玄学。
但是,细节会直接决定上限。
因此,你需要可复述的讲解模板。
同时,要把代码与表达一起训练。
此外,想做一对一实战复盘,请点击:联系我们的专家进行一对一面试辅导
与此同时,想补基础术语,可参考:权威算法参考