Reputation: 81
There's a group:
S = {(xi,yi)|1 ≤ i ≤ n}
of n points. There are no 2 points (xi,yi) (xj,yj) where xi = xj and yi = yj
.
It means the x and y values are unique. I need to find a data structure that supports the functions:
A simple solution will be to create two sorted arrays (one sorted according to the x values and the second sorted according to the y values). To find y with a given x will take O(logn)
, by using binary search. The same for finding x.
I can't use more than one array (of n elements) and each element is a point. I need to find an efficient data structure that can do those actions in an optimal time. I need to find:
T(first function)+T(second action)
.
Which data structure is the most efficient in this case?
Thank you very much.
Upvotes: 0
Views: 191
Reputation: 3457
Note: I dont read your condition '(xi, yi), (xj, yj) => xi != xj && yi != yj' as you do, to me this only means that the coordinates are unique (not each x and each y).
So you first must create a Point object
public class Point {
public int x;
public int y;
public Point(int x, int y) { this.x = x; this.y = y; }
}
Then store all your points into a unique array (you said you need it)
Point[] POINTS = ... // fill your array depending on your input
Finally wrap ths array into a class that provides the methods you need
public class PointCollection {
public Point[] points;
public Map<Integer, List<Integer>> mapX = new HashMap<Integer; List<Integer>>();
public Map<Integer, List<Integer>> mapY = new HashMap<Integer; List<Integer>>();
public PointCollection(Points[] points) {
this.points = points;
for (Point p : points) {
mapX.getOrDefault(p.x, new ArrayList<Integer>()).add(p.y);
mapY.getOrDefault(p.y, new ArrayList<Integer>()).add(p.x);
}
}
public int[] getMatchingY(int x) {
List<Integer> result = new ArrayList<Integer>();
for (Point p : this.points)) {
if (p.x == x) result.add(p.y);
}
return result.toArray(new int[result.size()]);
}
public int[] getMatchingX(int y) {
List<Integer> result = new ArrayList<Integer>();
for (Point p : this.points)) {
if (p.y == y) result.add(p.x);
}
return result.toArray(new int[result.size()]);
}
public int[] getMatchingYFromMap(int x) {
List<Integer> result = mapX.getOrDefault(x, new ArrayList<Integer>());
return result.toArray(new int[result.size()]);
}
public int[] getMatchingXFromMap(int y) {
List<Integer> result = mapY.getOrDefault(y, new ArrayList<Integer>());
return result.toArray(new int[result.size()]);
}
}
edit: added solution based on map
Upvotes: 0
Reputation: 140494
Fundamentally, you just need a pair of maps:
Map<TypeOfX, TypeOfY> mapXtoY;
Map<TypeOfY, TypeOfX> mapYtoX;
You can use any concrete implementation of Map
, e.g. HashMap
, TreeMap
, LinkedHashMap
...
To add a point, you simply add it to both:
void addPoint(TypeOfX x, TypeOfY y) {
mapXtoY.put(x, y);
mapYtoX.put(y, x);
}
And you can get the y
for an x
by using:
TypeOfY y = mapXtoY.get(x);
and vice versa.
Libraries such as Guava provide BiMap
implementations, which maintain this two-directional mapping for you.
Upvotes: 1