30. Проверить вертикальную симметрию набора точек
Условие задачи:
Дан массив точек с целочисленными координатами (x, y).
Необходимо определить, существует ли вертикальная прямая x = c, относительно которой весь набор точек симметричен.
Для каждой точки (x, y), не лежащей на оси симметрии, должна существовать зеркальная точка (2c - x, y) с такой же кратностью.
Дубликаты точек необходимо учитывать.
Код:
public class SymmetryChecker {
public static boolean isVertSym(int[][] points) {
// TODO
}
}
Примеры:
[[0, 0], [0, 1], [1, 1], [2, 2], [3, 1], [4, 1], [4, 0]] → true
[[0, 0], [0, 0], [1, 1], [2, 2], [3, 1], [4, 0], [4, 0]] → true
[[0, 0], [0, 0], [1, 1], [2, 2], [3, 1], [4, 0]] → false
[] → true
[[0, 0]] → true
[[0, 0], [10, 0]] → true
[[0, 0], [11, 1]] → false
[[0, 0], [1, 0], [3, 0]] → false
Спойлеры к решению
Подсказки
x.💡 Вместо самого
c удобно хранить значение 2 * c = minX + maxX.💡 Для каждой точки
(x, y) зеркальная точка имеет координаты (minX + maxX - x, y).💡 Используй
Map<Point, Integer>, чтобы учитывать несколько одинаковых точек.💡 Для суммы координат лучше использовать
long, чтобы избежать переполнения int.Решение
public static boolean isVertSym(int[][] points) {
if (points.length <= 1) {
return true;
}
int minX = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
Map<Point, Integer> frequencies = new HashMap<>();
for (int[] point : points) {
int x = point[0];
int y = point[1];
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
frequencies.merge(new Point(x, y), 1, Integer::sum);
}
long sum = (long) minX + maxX;
for (Map.Entry<Point, Integer> entry : frequencies.entrySet()) {
Point point = entry.getKey();
long mirrorX = sum - point.x;
if (mirrorX < Integer.MIN_VALUE
|| mirrorX > Integer.MAX_VALUE) {
return false;
}
Point mirror = new Point((int) mirrorX, point.y);
if (!Objects.equals(
frequencies.get(mirror),
entry.getValue()
)) {
return false;
}
}
return true;
}
private static class Point {
private final int x;
private final int y;
private Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Point)) {
return false;
}
Point other = (Point) obj;
return x == other.x && y == other.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
Если ось симметрии существует, она определяется крайними точками по x.
Например:
minX = 0
maxX = 4
Тогда:
2 * c = minX + maxX = 4
c = 2
Для точки:
(0, 1)
зеркальная координата вычисляется как:
x' = 4 - 0 = 4
поэтому должна существовать точка:
(4, 1)
Для точки на самой оси:
(2, 2)
получится:
x' = 4 - 2 = 2
то есть она зеркальна сама себе.
Важно учитывать не только наличие зеркальной точки, но и количество её вхождений. Например:
(0, 0) — 2 раза
(4, 0) — 1 раз
не образуют симметричный набор.
Поэтому сравниваются частоты:
if (!Objects.equals(
frequencies.get(mirror),
entry.getValue()
)) {
return false;
}
Временная сложность в среднем — O(n), дополнительная память — O(k), где k — количество различных точек.