LeetCode 296 - Best Meeting Point


[Leetcode] Best Meeting Point 最佳见面点 - SegmentFault
A group of two or more people wants to meet and minimize the total travel distance. You are given a 2D grid of values 0 or 1, where each 1 marks the home of someone in the group. The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|.
For example, given three people living at (0,0), (0,4), and (2,2):
1 - 0 - 0 - 0 - 1
|   |   |   |   |
0 - 0 - 0 - 0 - 0
|   |   |   |   |
0 - 0 - 1 - 0 - 0
The point (0,2) is an ideal meeting point, as the total travel distance of 2+2+2=6 is minimal. So return 6.
http://www.chenguanghe.com/best-meeting-point/
首先,Manhattan Distance 的合为 sum(distance(p1, p2)) = sum(|p2.x - p1.x| + |p2.y - p1.y|)= sum(|p2.x - p1.x|)+sum(|p2.y - p1.y|). 也就是说, 可以分别计算x和y的合, 然后加起来.
其次, 我们需要把2d的grid变成1d, 这里的窍门是, 我们可以证明, 所求的点, 就在其中某点的x或者y的坐标轴上. 所以, 而这点, 必然是1d下的median. http://math.stackexchange.com/questions/113270/the-median-minimizes-the-sum-of-absolute-deviations
Suppose we have a set S of real numbers that ∑s∈S|s−x|is minimal if x is equal to themedian.
所以, 我们需要count一下x轴上有多少个1的投影, 和y轴上有多少个1的投影. 就可以找到这个median. 这里我们不需要sorting, 因为投影本身就是已排序的.
最后, 我们得到一个1d的array, 我们需要计算以上公式,即各点到median的值的合, 这里需要用two pointers, 因为array本身已经是排序过后的了, 所以我们只需要求两头的元素的差值的合, 就是他们到median的合.
Image result for median
6是median,那么 (6-2)+(6-4) + (6-5) + (7-6) + (8-6) + (9-6) = 4 + 2+ 1+ 1+ 2+ 3 = 13 = (9-2) + (8-4) + (7-5)
public int minTotalDistance(int[][] grid) {
        ArrayList<Integer> r = new ArrayList<Integer>();
        ArrayList<Integer> l = new ArrayList<Integer>();
        for(int i = 0; i < grid.length; i++){
            for(int j = 0; j < grid[0].length; j++){
                if(grid[i][j] == 1)
                    r.add(i);
            }
        }// rename l, r to xs, ys. rename min to getDistance/
        for(int j = 0; j < grid[0].length; j++){// project to x or y axis
            for(int i = 0; i < grid.length; i++){
                if(grid[i][j] == 1)
                    l.add(j);
            }
        }
        return min(r)+min(l);
    }
    
    public int min(ArrayList<Integer> ary) {
        int i = 0;
        int j = ary.size()-1;
        int sum = 0;
        while(i < j){
            sum += (ary.get(j) -ary.get(i));
            i++;
            j--;
        }
        return sum;
    }
    public int minTotalDistance(int[][] grid) {
        List<Integer> ipos = new ArrayList<Integer>();
        List<Integer> jpos = new ArrayList<Integer>();
        // 统计出有哪些横纵坐标
        for(int i = 0; i < grid.length; i++){
            for(int j = 0; j < grid[0].length; j++){
                if(grid[i][j] == 1){
                    ipos.add(i);
                    jpos.add(j);
                }
            }
        }
        int sum = 0;
        // 计算纵坐标到纵坐标中点的距离,这里不需要排序,因为之前统计时是按照i的顺序
        for(Integer pos : ipos){
            sum += Math.abs(pos - ipos.get(ipos.size() / 2));
        }
        // 计算横坐标到横坐标中点的距离,这里需要排序,因为统计不是按照j的顺序
        Collections.sort(jpos);
        for(Integer pos : jpos){
            sum += Math.abs(pos - jpos.get(jpos.size() / 2));
        }
        return sum;
    }
http://www.cnblogs.com/grandyang/p/5291058.html
这道题让我们求最佳的开会地点,该地点需要到每个为1的点的曼哈顿距离之和最小,题目中给了我们提示,让我们先从一维的情况来分析,那么我们先看一维时有两个点A和B的情况,
______A_____P_______B_______
那么我们可以发现,只要开会为位置P在[A, B]区间内,不管在哪,距离之和都是A和B之间的距离,如果P不在[A, B]之间,那么距离之和就会大于A和B之间的距离,那么我们现在再加两个点C和D:
______C_____A_____P_______B______D______
我们通过分析可以得出,P点的最佳位置就是在[A, B]区间内,这样和四个点的距离之和为AB距离加上CD距离,在其他任意一点的距离都会大于这个距离,那么分析出来了上述规律,这题就变得很容易了,我们只要给位置排好序,然后用最后一个坐标减去第一个坐标,即CD距离,倒数第二个坐标减去第二个坐标,即AB距离,以此类推,直到最中间停止,那么一维的情况分析出来了,二维的情况就是两个一维相加即可,参见代码如下:

解法一:
复制代码
class Solution {
public:
    int minTotalDistance(vector<vector<int>>& grid) {
        vector<int> rows, cols;
        for (int i = 0; i < grid.size(); ++i) {
            for (int j = 0; j < grid[i].size(); ++j) {
                if (grid[i][j] == 1) {
                    rows.push_back(i);
                    cols.push_back(j);
                }
            }
        }
        return minTotalDistance(rows) + minTotalDistance(cols);
    }
    int minTotalDistance(vector<int> v) {
        int res = 0;
        sort(v.begin(), v.end());
        int i = 0, j = v.size() - 1;
        while (i < j) res += v[j--] - v[i++];
        return res;
    }
http://algobox.org/best-meeting-point/
Before solving the 2D problem we first consider a 1D case. The solution is quite simple. Just find the median of all the x coordinates and calculate the distance to the median.
Alternatively, we can also use two pointers to solve the 1D problem. left and right are how many people one left/right side of coordinates i/j. If we have more people on the left we let j decrease otherwise increase i. The time complexity is O(n) and space is O(1).
To be more clear, a better view is that we can think i and j as two meeting points. All the people in [0, i] meet ati and all the people in [j, n - 1] meet at j. We let left = sum(vec[:i+1])right = sum(vec[j:]), which are the number of people at each meet point, and d is the total distance for the left people meet at i and right people meet at j.
Our job is to let i == j with minimum d.
If we increase i by 1, the distance will increase by left since there are left people at i and they just move 1step. The same applies to j, when decrease j by 1, the distance will increase by right. To make sure the total distance d is minimized we certainly want to move the point with less people. And to make sure we do not skip any possible meet point options we need to move one by one.
For the 2D cases we first need to sum the columns and rows into two vectors and call the 1D algorithm. The answer is the sum of the two. The time is then O(mn) and extra space is O(m+n)
Moreover, the solution is still O(mn) with the follow up:
What if there are people sharing same home? In other words the number in the grid can be more than 1.
public int minTotalDistance(int[][] grid) {
    int m = grid.length, n = grid[0].length;
    int[] row_sum = new int[n], col_sum = new int[m];
    for (int i = 0; i < m; ++i)
        for (int j = 0; j < n; ++j) {
            row_sum[j] += grid[i][j];
            col_sum[i] += grid[i][j];
        }
    return minDistance1D(row_sum) + minDistance1D(col_sum);
}
public int minDistance1D(int[] vector) {
    int i = -1, j = vector.length;
    int d = 0, left = 0, right = 0;
    while (i != j) {
        if (left < right) {
            d += left;
            left += vector[++i];
        } else {
            d += right;
            right += vector[--j];
        }
    }
    return d;
}
http://www.cnblogs.com/jcliBlogger/p/4901473.html
Since the distance is computed using the Manhattan Distance, we can decompose this 2-d problem into two 1-d problems and combine (add) their solutions. In fact, the best meeting point is just the point that comprised by the two best meeting points in each dimension.

For the 1d case, the best meeting point is just the median point.
3     int minTotalDistance(vector<vector<int>>& grid) {
 4         int m = grid.size(), n = grid[0].size();
 5         vector<int> ii, jj;
 6         for (int i = 0; i < m; i++) {
 7             for (int j = 0; j < n; j++) {
 8                 if (grid[i][j]) {
 9                     ii.push_back(i);
10                     jj.push_back(j);
11                 }
12             }
13         } 
14         sort(jj.begin(), jj.end());
15         int c = ii.size(), s = 0, io = ii[c/2], jo = jj[c/2];
16         for (int i : ii) s += abs(i - io);
17         for (int j : jj) s += abs(j - jo);
18         return s;
19     }
https://leetcode.com/discuss/65366/o-mn-java-2ms
The neat total += Z[hi--] - Z[lo++]-style summing is from larrywang2014's solution.
Originally I used total += abs(Z[i] - median)-style.
public int minTotalDistance(int[][] grid) { int m = grid.length, n = grid[0].length; int total = 0, Z[] = new int[m*n]; for (int dim=0; dim<2; ++dim) { int i = 0, j = 0; if (dim == 0) { for (int x=0; x<n; ++x) for (int y=0; y<m; ++y) if (grid[y][x] == 1) Z[j++] = x; } else { for (int y=0; y<m; ++y) for (int g : grid[y]) if (g == 1) Z[j++] = y; } while (i < --j) total += Z[j] - Z[i++]; } return total; }

BucketSort-ish. Count how many people live in each row and each column. Only O(m+n) space.
public int minTotalDistance(int[][] grid) {
    int m = grid.length, n = grid[0].length;
    int[] I = new int[m], J = new int[n];
    for (int i=0; i<m; ++i)
        for (int j=0; j<n; ++j)
            if (grid[i][j] == 1) {
                ++I[i];
                ++J[j];
            }
    int total = 0;
    for (int[] K : new int[][]{ I, J }) {
        int i = 0, j = K.length - 1;
        while (i < j) {
            int k = Math.min(K[i], K[j]);
            total += k * (j - i);
            if ((K[i] -= k) == 0) ++i;
            if ((K[j] -= k) == 0) --j;
        }
    }
    return total;
}

https://zyfu0408.gitbooks.io/interview-preparation/content/zhao_ju_zhen_li_de_kong_jian_shang_de_zhong_dian_f.html
如果只有一个点,best meeting point就在点上;如果有两个点,best meeting point 是这两点之间任意点;如果是三个点,best meeting point是在中间的那个点上;如果是N个点,如果N是偶数,best meeting point 是在最内层的两个点之间的任意点;如果是N是奇数,best meeting point是最中间那个点。所以可以得出结论,找到中点就可以使得总距离最短。

    public int minTotalDistance(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
            return 0;
        }

        List<Integer> rows = new ArrayList<Integer>();
        List<Integer> cols = new ArrayList<Integer>();
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1) {
                    rows.add(i);
                    cols.add(j);
                }
            }
        }

        Collections.sort(cols); // sort的这一步可以用quickselect来优化。
        int row_mid = rows.get(rows.size() / 2);
        int col_mid = cols.get(cols.size() / 2);

        int sum = 0;
        for (int i = 0; i < rows.size(); i++) {
            sum += Math.abs(row_mid - rows.get(i));
        }
        for (int i = 0; i < cols.size(); i++) {
            sum += Math.abs(col_mid - cols.get(i));
        }

        return sum;
    }
https://leetcode.com/discuss/65510/simple-java-code-without-sorting
http://buttercola.blogspot.com/2015/10/leetcode-best-meeting-point.html


Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts