[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 }

原文地址:https://www.cnblogs.com/lz87/p/10351395.html

时间: 2024-10-09 10:00:03

[Daily Coding Problem 68] Count Pairs of attacking bishop pairs的相关文章

[Daily Coding Problem 290] Quxes Transformation

On a mysterious island there are creatures known as Quxes which come in three colors: red, green, and blue. One power of the Qux is that if two of them are standing next to each other, they can transform into a single creature of the third color. Giv

[Daily Coding Problem] 1 (LeetCode 1). Find if two numbers in an array add up to k

This problem was recently asked by Google. Given a list of numbers and a number k, return whether any two numbers from the list add up to k. For example, given [10, 15, 3, 7] and k of 17, return true since 10 + 7 is 17. Bonus: Can you do this in one

[Daily Coding Problem 70] Nth perfect number

This problem was asked by Microsoft. A number is considered perfect if its digits sum up to exactly 10. Given a positive integer n, return the n-th perfect number. For example, given 1, you should return 19. Given 2, you should return 28. This is one

Daily Coding Problem: Problem #315

/** * This problem was asked by Google. In linear algebra, a Toeplitz matrix is one in which the elements on any given diagonal from top left to bottom right are identical. Here is an example: 1 2 3 4 8 5 1 2 3 4 4 5 1 2 3 7 4 5 1 2 Write a program t

[Daily Coding Problem 223] O(1) space in order traversal of a binary tree

Typically, an implementation of in-order traversal of a binary tree has O(h) space complexity, where h is the height of the tree. Write a program to compute the in-order traversal of a binary tree using O(1) space. In-order traversal without recursio

Daily Coding Problem: Problem #339

/** * This problem was asked by Microsoft. Given an array of numbers and a number k, determine if there are three entries in the array which add up to the specified number k. For example, given [20, 303, 3, 4, 25] and k = 49, return true as 20 + 4 +

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

A competitive runner would like to create a route that starts and ends at his house, with the condition that the route goes entirely uphill at first, and then entirely downhill. Given a dictionary of places of the form {location: elevation}, and a di

[Daily Coding Problem] Find the total number of solutions of a linear equation of n variables

Given a linear equation of n variables, find the total number of non-negative integer solutions of it. All coefficients are positive. Example: input: x + 2 * y = 5 output: 3,  the 3 possible integer solutions are x = 1, y = 2; x = 3, y = 1; x = 5, y

[Daily Coding Problem 250] Cryptarithmetic Puzzle

A cryptarithmetic puzzle is a mathematical game where the digits of some numbers are represented by letters. Each letter represents a unique digit. For example, a puzzle of the form: SEND + MORE -------- MONEY may have the solution: {'S': 9, 'E': 5,