[Daily Coding Problem 68] Count Pairs of attacking bishop pairs

Posted lz87

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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 }

 

以上是关于[Daily Coding Problem 68] Count Pairs of attacking bishop pairs的主要内容,如果未能解决你的问题,请参考以下文章

Daily Coding Problem: Problem #339

[Daily Coding Problem 290] Quxes Transformation

[Daily Coding Problem 250] Cryptarithmetic Puzzle

[Daily Coding Problem 70] Nth perfect number

[Daily Coding Problem 24] Implement locking in a binary tree.

[Daily Coding Problem 294] Shortest round route with rising then falling elevations