rotemhas
rotemhas

Reputation: 81

How to find y when x is given and a list of points?

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:

  1. Given x, return the value of y where (x,y) is in S. If it doesn't exist return "not exist".
  2. Given y, return the value x where (x,y) is in S. If it doesn't exist return "not exist".

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

Answers (2)

Ji aSH
Ji aSH

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

Andy Turner
Andy Turner

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

Related Questions