zoukankan      html  css  js  c++  java
  • [Daily Coding Problem 68] Count Pairs of attacking bishop pairs

    This problem was asked by Google.

    On our special chessboard, two bishops attack each other if they share the same diagonal. This includes bishops that have another bishop located between them, i.e. bishops can attack through pieces.

    You are given N bishops, represented as (row, column) tuples on a M by M chessboard. Write a function to count the number of pairs of bishops that attack each other. The ordering of the pair doesn't matter: (1, 2) is considered the same as (2, 1).

    For example, given M = 5 and the list of bishops:

    • (0, 0)
    • (1, 2)
    • (2, 2)
    • (4, 0)

    The board would look like this:

    [b 0 0 0 0]
    [0 0 b 0 0]
    [0 0 b 0 0]
    [0 0 0 0 0]
    [b 0 0 0 0]
    

    You should return 2, since bishops 1 and 3 attack each other, as well as bishops 3 and 4.

    The naive solution is to check each pair of all possible pairs. Its runtime is O(N^2). Can we make this any faster?

    The bottle neck of the naive solution is that on a particular diagonal, if there are m bishops, then it takes m * (m - 1) / 2, which is O(m^2) time. It does not use the information that all of these bishops are in fact on the same diagonal already. A better solution is to go through each bishop and bucket them into each separate diagonal. For each diagonal with m bishops on it, there are m * (m - 1) / 2 attacking pairs. This reduces the runtime of getting all attacking pairs from one diagonal to O(m). 

    Now we just need to find a good way of bucketing all bishops. We need a slope and a point to definitively specify a line in a 2D-coordinates. In this case, there can be only 2 slopes, +1 or -1.  And we can use the boundary coordinates of the chessboard to bucket each bishops.

    For bishop (x, y),

    1. when the slope is 1, if x > y, the boundary point is (x - y, y - y); else the boundary point is (x - x, y - x); so boundary point is (x - min(x, y), y - min(x, y)).

    2. when the slope is -1, if x > y, the boundary point is (x - x, y + x); else the boundary point is (x - (M - y), y + (M -y)); so the boundary point is (x - min(x, M - y), y + min(x, M - y)).

    We can use two maps of map save the diagonals buckets. We must use 2 separate maps, 1 for each slope because for each boundary point, there are 2 possilbe diagonals, one with slope 1, one with slope -1.

     1 public class AttackingBishop {
     2     class Point {
     3         int x, y;
     4     }
     5     public int countAttackingBishopPairs(Point[] points, int M) {
     6         Map<Integer, Map<Integer, Integer>> posMap = new HashMap<>();
     7         Map<Integer, Map<Integer, Integer>> negMap = new HashMap<>();
     8         for(Point point : points) {
     9             int posBoundaryX = point.x - Math.min(point.x, point.y);
    10             int posBoundaryY = point.y - Math.min(point.x, point.y);
    11             int negBoundaryX = point.x - Math.min(point.x, M - point.y);
    12             int negBoundaryY = point.y + Math.min(point.x, M - point.y);
    13 
    14             if(!posMap.containsKey(posBoundaryX)) {
    15                 posMap.put(posBoundaryX, new HashMap<>());
    16             }
    17             if(!posMap.get(posBoundaryX).containsKey(posBoundaryY)) {
    18                 posMap.get(posBoundaryX).put(posBoundaryY, 0);
    19             }
    20             Map<Integer, Integer> map = posMap.get(posBoundaryX);
    21             map.put(posBoundaryY, map.get(posBoundaryY) + 1);
    22 
    23             if(!negMap.containsKey(negBoundaryX)) {
    24                 negMap.put(negBoundaryX, new HashMap<>());
    25             }
    26             if(!negMap.get(negBoundaryX).containsKey(negBoundaryY)) {
    27                 negMap.get(negBoundaryX).put(negBoundaryY, 0);
    28             }
    29             map = negMap.get(negBoundaryX);
    30             map.put(negBoundaryY, map.get(negBoundaryY) + 1);
    31         }
    32         int count = 0;
    33         for(Map<Integer, Integer> map : posMap.values()) {
    34             for(int c : map.values()) {
    35                 count += c * (c - 1) / 2;
    36             }
    37         }
    38         for(Map<Integer, Integer> map : negMap.values()) {
    39             for(int c : map.values()) {
    40                 count += c * (c - 1) / 2;
    41             }
    42         }
    43         return count;
    44     }
    45 }

    A more concise implementation is to customize your own key and only use a hash map.

     1 public class AttackingBishop {
     2     class Point {
     3         int x, y;
     4 
     5         Point(int x, int y) {
     6             this.x = x;
     7             this.y = y;
     8         }
     9 
    10         @Override
    11         public int hashCode() {
    12             return 31 * x + 37 * y;
    13         }
    14 
    15         @Override
    16         public boolean equals(Object obj) {
    17             if (this == obj) {
    18                 return true;
    19             }
    20             if (obj == null || getClass() != obj.getClass()) {
    21                 return false;
    22             }
    23             Point p = (Point) obj;
    24             if (x != p.x || y != p.y) {
    25                 return false;
    26             }
    27             return true;
    28         }
    29     }
    30 
    31     public int countAttackingBishopPairs(Point[] points, int M) {
    32         Map<Point, Integer> posMap = new HashMap<>();
    33         Map<Point, Integer> negMap = new HashMap<>();
    34         for (Point point : points) {
    35             Point p1 = new Point(point.x - Math.min(point.x, point.y), point.y - Math.min(point.x, point.y));
    36             Point p2 = new Point(point.x - Math.min(point.x, M - point.y), point.y + Math.min(point.x, M - point.y));
    37             if (!posMap.containsKey(p1)) {
    38                 posMap.put(p1, 1);
    39             } else {
    40                 posMap.put(p1, posMap.get(p1) + 1);
    41             }
    42             if (!negMap.containsKey(p2)) {
    43                 negMap.put(p2, 1);
    44             } else {
    45                 negMap.put(p2, negMap.get(p2) + 1);
    46             }
    47         }
    48         int count = 0;
    49         for (int c : posMap.values()) {
    50             count += c * (c - 1) / 2;
    51         }
    52         for (int c : negMap.values()) {
    53             count += c * (c - 1) / 2;
    54         }
    55         return count;
    56     }
    57 }
  • 相关阅读:
    web.config配置数据库连接 【转】
    WEB API 返回类型设置为JSON 【转】
    ASP.NET WebAPI 路由规则与POST数据 【转】
    ASP.NET Web API路由规则(二) 【转】
    七天学会ASP.NET MVC(七)——创建单页应用 【转】
    jumpserver-v0.5.0 应用图解
    jumpserverv0.5.0 基于 CentOS7安装部署
    tar: Removing leading `/' from member names
    redis cli命令
    zabbix监控redis的key值
  • 原文地址:https://www.cnblogs.com/lz87/p/10351395.html
Copyright © 2011-2022 走看看