题目地址:
https://leetcode.com/problems/line-reflection/
给定二维平面 n n n个点,问是否存在一个竖直的直线,使得这些点关于这条直线做镜面反射后,得到的点与之前重合。如果有两个点在相同位置我们视为是一个点。
先找到 x x x坐标最大和最小的点,设它们的 x x x坐标分别是 x 1 x_1 x1和 x 2 x_2 x2,那么如果能重合,镜面反射的中轴线一定是 x = x 1 + x 2 2 x=\frac{x_1+x_2}{2} x=2x1+x2,也就是如果两个点 y y y坐标相同,它们关于这个中轴线对称当且仅当它们的 x x x坐标之和是 x 1 + x 2 x_1+x_2 x1+x2。我们可以开个哈希表,key是 y y y坐标,value是以key为 y y y坐标的所有点的 x x x坐标组成的列表,遍历所有点并存入哈希表,然后遍历哈希表,每次遍历的时候,将value的列表排序,然后用对撞双指针判断是否 x x x坐标之和恰好是 x 1 + x 2 x_1+x_2 x1+x2即可。注意要略过重复的点。代码如下:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Solution {
public boolean isReflected(int[][] points) {
if (points.length == 0) {
return true;
}
int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE;
for (int[] point : points) {
minX = Math.min(minX, point[0]);
maxX = Math.max(maxX, point[0]);
}
int sumX = minX + maxX;
Map<Integer, List<Integer>> map = new HashMap<>();
for (int[] point : points) {
map.putIfAbsent(point[1], new ArrayList<>());
map.get(point[1]).add(point[0]);
}
for (Map.Entry<Integer, List<Integer>> entry : map.entrySet()) {
List<Integer> list = entry.getValue();
list.sort(null);
for (int i = 0, j = list.size() - 1; i <= j; i++, j--) {
// 从左向右找到重复点中的最后一个
while (i + 1 < list.size() && list.get(i) == list.get(i + 1)) {
i++;
}
// 从右向左找到重复点中的最后一个
while (j > 0 && list.get(j) == list.get(j - 1)) {
j--;
}
if (list.get(i) + list.get(j) != sumX) {
return false;
}
}
}
return true;
}
}
时间复杂度 O ( ∑ x i log x i ) O(\sum x_i\log x_i) O(∑xilogxi), x i x_i xi代表 y y y相同的点的个数,空间 O ( n ) O(n) O(n)。