← 返回博客列表
DoorDash

DoorDash VO:最近同軸城市

2025-11-23

oavoservice 原創復盤:重點在「如何把候選縮到常數個」,以及 tie-break 的實作細節。

題目(改寫版)

給定 n 個城市座標:(x[i], y[i]),以及 q 個查詢城市名。

對每個查詢城市 c

思路核心

如果每次查詢都掃一遍 n,會變成 O(nq)

優化:

對查詢城市,只需要在兩條有序列表裡找它的相鄰前驅/後繼,最多比較 4 個候選。

資料結構

複雜度

Python 參考實作

from bisect import bisect_left
from collections import defaultdict


def closest_straight_city(names, xs, ys, queries):
    pos = {}
    x_map = defaultdict(list)
    y_map = defaultdict(list)

    for name, x, y in zip(names, xs, ys):
        pos[name] = (x, y)
        x_map[x].append((y, name))
        y_map[y].append((x, name))

    for x in x_map:
        x_map[x].sort()  # (y, name)
    for y in y_map:
        y_map[y].sort()  # (x, name)

    def pick_best(candidates, x0, y0):
        best = None
        best_dist = None
        for name, x, y in candidates:
            dist = abs(x - x0) + abs(y - y0)
            if best is None or dist < best_dist or (dist == best_dist and name < best):
                best = name
                best_dist = dist
        return best

    ans = []
    for q in queries:
        if q not in pos:
            ans.append("NONE")
            continue

        x0, y0 = pos[q]
        candidates = []

        # 同 x:在按 y 排序列表裡找鄰居
        lst = x_map.get(x0, [])
        i = bisect_left(lst, (y0, q))
        for j in (i - 1, i + 1):
            if 0 <= j < len(lst):
                y, name = lst[j]
                if name != q:
                    candidates.append((name, x0, y))

        # 同 y:在按 x 排序列表裡找鄰居
        lst = y_map.get(y0, [])
        i = bisect_left(lst, (x0, q))
        for j in (i - 1, i + 1):
            if 0 <= j < len(lst):
                x, name = lst[j]
                if name != q:
                    candidates.append((name, x, y0))

        best = pick_best(candidates, x0, y0)
        ans.append(best if best is not None else "NONE")

    return ans

常見坑


如果你在準備 DoorDash VO,這題在面試裡常被用來考你是否能把「全域掃描」改造成「索引 + 鄰居候選」。oavoservice 會重點訓練這種「把候選縮到常數個」的套路。


需要面試真題? 立刻聯繫微信 Coding0201獲得真題