Nearest Cities

// A number of cities are arranged on a graph that has been divided up like an ordinary Cartesian plane.
// Each city is located at an integral(x, y) coordinate intersection.

// City names and locations are given in the form of three arrays : c, x, and y, which are aligned by the index to provide the city name(c[i]), and its coordinates, (x[i], y[i]).
// Determine the name of the nearest city that shares either an x or a y coordinate with the queried city.

// If no other cities share an x or y coordinate, return 'NONE'.

// If two cities have the same distance to the queried city, q[i], consider the one with an alphabetically shorter name(i.e. 'ab' < 'aba' < 'abb') as the closest choice.
// The distance is the Manhattan distance, the absolute difference in x plus the absolute difference in y.

// The time complexity for my solution is O(NlogK) for processing input + O(QlogK) for returning the result for all the given queries,
// where N is the number of cities, K is the max number of cities with same x or y coordinate and Q is the number of queries.

// 题目就是给两个城市的list,一个是所有城市c[c1, c2, c3, c4],x[4, 7, 9], y[1, 2, 3],一个是需要query求距离的城市q[c3, c4],求q里面每个城市到x或者y坐标重合(指 x相等或者y相等)的城市到最短距离
// 解法就是用map记录{ x1: [c1, c2, c3] }  c1, c2, c3都有相同x1,sorted by y value in the list, 在query 一个城市q(qx, qy)的时候,求qx‍‍‍‍‍‍‍‌‍‌‌‌‌‍‍‌‌‌在map对应的list里面离qy最近的距离,用二分法求

// 给一组城市name 坐标x 坐标y 输入一系列query name 返回相同x或者相同y的最近city name
// every city name is guaranteed to be unique and no 2 cities will have same coordinates

// 如果没有则返回\'NONE\'
// 注意如果有相同的最近的城市,返回alphabet更小的城市
// 我的做法 复杂度nlog(n)

#include <iostream>
#include <vector>
#include <map>
#include <limits>
#include <string>
#include <cmath>

using namespace std;

struct CityDist {
    double dist;
    string city;

    CityDist(double dist, string city) : dist(dist), city(city) {}
};
class NearestCity {
public:
    // Time: O(nlogn), Space: O(n)
    vector<string> getNearestCities(vector<string>& names, vector<int>& x, vector<int>& y, vector<string>& query) {
        unordered_map<int, map<int, string>> sameXCityMap;
        unordered_map<int, map<int, string>> sameYCityMap;
        unordered_map<string, pair<int, int>> nameToXYMap;

        for (size_t i = 0; i < names.size(); ++i) {
            sameXCityMap[x[i]][y[i]] = names[i];
            sameYCityMap[y[i]][x[i]] = names[i];
            nameToXYMap[names[i]] = { x[i], y[i] };
        }

        vector<string> res;
        for (const string& queriedCity : query) {
            CityDist minCityDist(std::numeric_limits<double>::max(), "NONE");
            auto queriedLocation = nameToXYMap[queriedCity];
            int queriedX = queriedLocation.first, queriedY = queriedLocation.second;

            updateCloserCity(sameXCityMap[queriedX], queriedY, minCityDist);
            updateCloserCity(sameYCityMap[queriedY], queriedX, minCityDist);

            res.push_back(minCityDist.city);
        }
        return res;
    }

    void updateCloserCity(const map<int, string>& cities, int queriedCoord, CityDist& minCityDist) {
        auto lower = cities.lower_bound(queriedCoord);
        auto upper = cities.upper_bound(queriedCoord);

        if (lower != cities.begin()) {
            --lower;
            double dist = abs(lower->first - queriedCoord);
            if (dist < minCityDist.dist || (dist == minCityDist.dist && lower->second < minCityDist.city)) {
                minCityDist.dist = dist;
                minCityDist.city = lower->second;
            }
        }

        if (upper != cities.end()) {
            double dist = abs(upper->first - queriedCoord);
            if (dist < minCityDist.dist || (dist == minCityDist.dist && upper->second < minCityDist.city)) {
                minCityDist.dist = dist;
                minCityDist.city = upper->second;
            }
        }
    }
};

int main() {
    // city1: (1, 1)
    // city2: (1, 5)
    // city3: (2, 3)
    // city4: (3, 1)
    NearestCity solver1;
    vector<string> names1 = { "city1", "city2", "city3", "city4" };
    vector<int> x1 = { 1, 1, 2, 3 };
    vector<int> y1 = { 1, 5, 3, 1 };
    vector<string> query1 = { "city1", "city2", "city3", "city4" };

    vector<string> nearestCities1 = solver1.getNearestCities(names1, x1, y1, query1);

    cout << "Test Case 1:" << endl;
    for (const auto& city : nearestCities1) {
        cout << city << endl;
    }
    cout << endl;

    // alpha: (0, 0): beta
    // beta: (0, 2): alpha
    // gamma: (2, 2): beta
    // delta: (2, 0): alpha
    NearestCity solver2;
    vector<string> names2 = { "alpha", "beta", "gamma", "delta" };
    vector<int> x2 = { 0, 0, 2, 2 };
    vector<int> y2 = { 0, 2, 2, 0 };
    vector<string> query2 = { "alpha", "beta", "gamma", "delta" };

    vector<string> nearestCities2 = solver2.getNearestCities(names2, x2, y2, query2);

    cout << "Test Case 2:" << endl;
    for (const auto& city : nearestCities2) {
        cout << city << endl;
    }
    cout << endl;

    // north: (5, 10): center
    // south: (5, 5) : center
    // east: (10, 5) : south
    // west: (0, 5) : south
    // center: (5, 6) : south
    NearestCity solver3;
    vector<string> names3 = { "north", "south", "east", "west", "center" };
    vector<int> x3 = { 5, 5, 10, 0, 5 };
    vector<int> y3 = { 10, 5, 5, 5, 6 };
    vector<string> query3 = { "north", "south", "east", "west", "center" };

    vector<string> nearestCities3 = solver3.getNearestCities(names3, x3, y3, query3);

    cout << "Test Case 3:" << endl;
    for (const auto& city : nearestCities3) {
        cout << city << endl;
    }
    cout << endl;

    return 0;
}

Last updated