Representing a directed acyclic graph as a 2-dimensional array in Java - java

How can I represent a directed acyclic graph as a 2-dimensional array if each row contains the immediate out-neighbours of a particular node. For example, if I have an array int [] [] edges, edges[0] = {1,2,3} means there are edges from node 0 to nodes 1, 2 and 3.

If you have to use a 2D array - given that a 2D array at least in Java can't be sparse - then you need to allocate an NxN array: boolean[][] edges = new boolean[n][n];
You need to allow for the degenerate case where all the nodes are
in a single chain, hence you need n-1 rows.
You need to allow for a star rooted on any node, hence n-1 columns.
It's vastly more complicated to store addresses in an array - given that the size has to be so large anyway - than to simple store "yes" at row j, position k for an edge from j -> k. And it's a lot faster to update the latter.
Obviously the sensible approach would be a HashMap from source node to a HashSet of target nodes, but that's apparently not what you're looking for.

int n;
List<Integer>[] adj;
AdjacencyLists(int n) {
adj = (List<Integer>[])new List[n];
for (int i = 0; i < n; i++)
adj[i] = new ArrayList<Integer>(Integer.class);
}
.....
adj[a].add(b); // a -> b edge

Related

Find m elements in n arrays by picking at most 1 element out of each of the n arrays

I have n arrays, each of them contain an arbitrary amount of integers. No duplicates are possible within an array ([1,1,2] can't be one of the n arrays).
I also have an integer array of size m which is filled with integers from 1 to m (value_of_an_array_entry = array_index+1). Example: m = 4, the appropriate array is [1,2,3,4].
My question:
For given n and m, is it possible to find every element in the m array by picking at most 1 element out of each of the n arrays?
An Example:
n = 3, m = 3,
The n arrays: [1], [1, 2], [2, 3]
Output should be: Yes
(because we can find every element in the m array by picking at most 1 element out of each of the n arrays. Look at the n arrays and pick 1 from the first array, 2 from the second and 3 from the third array.)
This is an interview question, I received a hint to think about the Max flow problem (I don't see how this helps me).
You can build a graph like this: The graph is divided into the left part and the right part. The left part contains n vertices which represent the n arrays. The right part contains m vertices which represent the m numbers.
Then we consider these n arrays. If element k is contained in the i-th array, we draw an edge between the i-th vertex from the left and the k-th vertex from the right. Our goal is to choose m edges, so that each of the m vertices on the right is covered by the m edges exactly once, and the vertices on the left is covered at most once. This is a bipartite graph maximum matching problem, which can be solved by many algorithms, including max flow.
I think a recursive method should do it.
If m is an empty list, PASS
Otherwise, look for members of m containing the first element of m
if none found: FAIL
for each one found:
this member of m is part of a PASS if there is a PASS for m' = tail(m) and n' = other members of (n)
I haven't tested this, but:
public boolean check(List<Integer> m, List<List<Integer>> n) {
if (m.isEmpty()) {
return true;
}
int head = head(m);
List<Integer> tail = tail(m);
for (List<Integer> nMember : n) {
if (nMember.contains(head) && check(tail, nMinus(n, nMember))) {
return true;
}
}
return false;
}
Assumed methods:
head() returns the first element of the passed list.
tail() returns the passed list with the first element removed.
nMinus() returns a view or copy of n with nMember removed. It should not modify n.
You should use immutable collections, or at least treat them as immutable. Guava provides classes that would probably be useful. But you could quite trivially knock up a ListOmitting list wrapper class with which to implement nMinus() without Guava.
I can't say for sure it's not too brute-forcey, but it "feels" adequately efficient for an interview answer to me.

Vector of linked list

How to create vector of linked list in Java using Collections?
So far I have written the following code:
Vector <LinkedList <Integer> > adj = new Vector<>();
However I am unable to figure out how to initialize the vector with head nodes of the linked list.
What I want is given an integer N, I wish to initialize the vector with the values 0 to N-1 as the head nodes:
e.g given N = 4
vector ---> 0
1
2
3
So that later I can add members to the list when needed like :
vector ---> 0->2->3
1->3
2->0->1
3->1
With the code you have written, you have created an empty vector - you have to fill it with desired number of LinkedList instances (I am guessing you are a C++ programmer, where the vector would initialize "automatically"?). E.g. initialize your vector like this:
int N = 4;
Vector<LinkedList<Integer>> adj = new Vector<>(N); // N here isn't really needed, but it sets the initial capacity of the vector
for (int i = 0; i < 4; i++) {
ajd.add(new LinkedList<>());
}
Also, as Turing85 pointed out, you should use ArrayList if you don't need the synchronization.

What is the best way to represent a tree in this case?

I am trying to solve this question: https://www.hackerrank.com/challenges/journey-to-the-moon I.e. a problem of finding connected components of a graph. What I have is a list of vertices (from 0 to N-1) and each line in the standard input gives me pair of vertices that are connected by an edge (i.e. if I have 1, 3) it means that vertex 1 and vertex 3 are in one connected component. My question is what is the best way to store the inpit, i.e. how to represent my graph? My idea is to use ArrayList of Arraylist - each position in the array list stores another arraylist of adgecent vertices. This is the code:
public static List<ArrayList<Integer>> graph;
and then in the main() method:
graph = new ArrayList<ArrayList<Integer>>(N);
for (int j = 0; j < N; j++) {
graph.add(new ArrayList<Integer>());
}
//then for each line in the standard input I fill the corresponding values in the array:
for (int j = 0; j < I; j++) {
String[] line2 = br.readLine().split(" ");
int a = Integer.parseInt(line2[0]);
int b = Integer.parseInt(line2[1]);
graph.get(a-1).add(b);
graph.get(b-1).add(a);
}
I'm pretti sure that for solving the question I have to put vertex a at position b-1 and then vertex b at position a-1 so this should not change. But what I am looking for is better way to represent the graph?
Using Java's collections (ArrayList, for example) adds a lot of memory overhead. each Integer object will take at least 12 bytes, in addition to the 4 bytes required for storing the int.
Just use a huge single int array (let's call it edgeArray), which represents the adjacency matrix. Enter 1 when the cell corresponds to an edge. e.g., if nodes k and m is seen on the input, then cell (k, m) will have 1, else 0. In the row major order, it will be the index k * N + m. i.e, edgeArray[k * N + m ] = 1. You can either choose column major order, or row major order. But then your int array will be very sparse. It's trivial to implement a sparse array. Just have an array for the non-zero indices in sorted order. It should be in sorted order so that you can binary search. The number of elements will be in the order of number of edges.
Of course, when you are building the adjacency matrix, you won't know how many edges are there. So you won't be able to allocate the array. Just use a hash set. Don't use HashSet, which is very inefficient. Look at IntOpenHashSet from fastutils. If you are not allowed to use libraries, implement one that is similar to that.
Let us say that the openHashMap variable you will be using is called adjacencyMatrix. So if you see, 3 and 2 and there are 10^6 nodes in total (N = 10^6). then you will just do
adjacencyMatirx.add(3 * 10000000 + 2);
Once you have processed all the inputs, then you can make the sparse adjacency matrix implementation above:
final int[] edgeArray = adjacencyMatrix.toIntArray(new int[adjacencyMatrix.size()]);
IntArrays.sort(edgeArray)
Given an node, finding all adjacent nodes:
So if you need all the nodes connected to node p, you would binary search for the next value that is greater than or equal to p * N (O(log (number of edges))). Then you will just traverse the array until you hit a value that is greater than or equal to (p + 1) * N. All the values you encounter will be nodes connected to p.
Comparing it with the approach you mentioned in your question:
It uses O(N*b) space complexity, where N (number of nodes) and b is the branching factor. It's lower bounded by the number of edges.
For the approach I mentioned, the space complexity is just O(E). In fact it's exactly e number of integers plus the header for the int array.
I used var graph = new Dictionary<long, List<long>>();
See here for complete solution in c# - https://gist.github.com/newton3/a4a7b4e6249d708622c1bd5ea6e4a338
PS - 2 years but just in case someone stumbles into this.

Efficiently determine the parity of a permutation

I have an int[] array of length N containing the values 0, 1, 2, .... (N-1), i.e. it represents a permutation of integer indexes.
What's the most efficient way to determine if the permutation has odd or even parity?
(I'm particularly keen to avoid allocating objects for temporary working space if possible....)
I think you can do this in O(n) time and O(n) space by simply computing the cycle decomposition.
You can compute the cycle decomposition in O(n) by simply starting with the first element and following the path until you return to the start. This gives you the first cycle. Mark each node as visited as you follow the path.
Then repeat for the next unvisited node until all nodes are marked as visited.
The parity of a cycle of length k is (k-1)%2, so you can simply add up the parities of all the cycles you have discovered to find the parity of the overall permutation.
Saving space
One way of marking the nodes as visited would be to add N to each value in the array when it is visited. You would then be able to do a final tidying O(n) pass to turn all the numbers back to the original values.
I selected the answer by Peter de Rivaz as the correct answer as this was the algorithmic approach I ended up using.
However I used a couple of extra optimisations so I thought I would share them:
Examine the size of data first
If it is greater than 64, use a java.util.BitSet to store the visited elements
If it is less than or equal to 64, use a long with bitwise operations to store the visited elements. This makes it O(1) space for many applications that only use small permutations.
Actually return the swap count rather than the parity. This gives you the parity if you need it, but is potentially useful for other purposes, and is no more expensive to compute.
Code below:
public int swapCount() {
if (length()<=64) {
return swapCountSmall();
} else {
return swapCountLong();
}
}
private int swapCountLong() {
int n=length();
int swaps=0;
BitSet seen=new BitSet(n);
for (int i=0; i<n; i++) {
if (seen.get(i)) continue;
seen.set(i);
for(int j=data[i]; !seen.get(j); j=data[j]) {
seen.set(j);
swaps++;
}
}
return swaps;
}
private int swapCountSmall() {
int n=length();
int swaps=0;
long seen=0;
for (int i=0; i<n; i++) {
long mask=(1L<<i);
if ((seen&mask)!=0) continue;
seen|=mask;
for(int j=data[i]; (seen&(1L<<j))==0; j=data[j]) {
seen|=(1L<<j);
swaps++;
}
}
return swaps;
}
You want the parity of the number of inversions. You can do this in O(n * log n) time using merge sort, but either you lose the initial array, or you need extra memory on the order of O(n).
A simple algorithm that uses O(n) extra space and is O(n * log n):
inv = 0
mergesort A into a copy B
for i from 1 to length(A):
binary search for position j of A[i] in B
remove B[j] from B
inv = inv + (j - 1)
That said, I don't think it's possible to do it in sublinear memory. See also:
https://cs.stackexchange.com/questions/3200/counting-inversion-pairs
https://mathoverflow.net/questions/72669/finding-the-parity-of-a-permutation-in-little-space
Consider this approach...
From the permutation, get the inverse permutation, by swapping the rows and
sorting according to the top row order. This is O(nlogn)
Then, simulate performing the inverse permutation and count the swaps, for O(n). This should give the parity of the permutation, according to this
An even permutation can be obtained as the composition of an even
number and only an even number of exchanges (called transpositions) of
two elements, while an odd permutation be obtained by (only) an odd
number of transpositions.
from Wikipedia.
Here's some code I had lying around, which performs an inverse permutation, I just modified it a bit to count swaps, you can just remove all mention of a, p contains the inverse permutation.
size_t
permute_inverse (std::vector<int> &a, std::vector<size_t> &p) {
size_t cnt = 0
for (size_t i = 0; i < a.size(); ++i) {
while (i != p[i]) {
++cnt;
std::swap (a[i], a[p[i]]);
std::swap (p[i], p[p[i]]);
}
}
return cnt;
}

Iterating over bidimensional Java arrays

public static List<Vertex<Integer>> petersenGraph() {
List<Vertex<Integer>> v = new ArrayList<Vertex<Integer>>();
for (int i = 0; i < 10; i++) {
v.add(new Vertex<Integer>(i));
}
int[][] edges =
{{0,1}, {1,0}, {1,2}, {2,1}, {2,3}, {3,2}, {3,4}, {4,3}, {4,0}, {0,4},
{5,6}, {6,5}, {6,7}, {7,6}, {7,8}, {8,7}, {8,9}, {9,8}, {9,5}, {5,9},
{5,0}, {0,5}, {6,2}, {2,6}, {7,4}, {4,7}, {8,1}, {1,8}, {9,3}, {3,9}};
for (int[] e : edges)
v.get(e[0]).successors().add(v.get(e[1]));
return v;
}
I understand everything up to the point where there's the for which iterates over the edges. What is exactly is going on there?
edit: why are they accessed using e[0] and e[1]? is e[0] the first number and e[1] the second?
Argh, that's ugly.
edges is a bidimensional array, so it is an array of int arrays. In the actual definition, it is an array of pairs.
The line for (int[] e: edges) simply means that in each iteration, e will become a different array of ints, so in each iteration it is a different pair.
Then, e[0] represents the first item in the pair and e[1] represents the other.
So the first coordinate is used to look up a vertex, and then something happens and the second coordinate gets added in. Without seeing vertex or knowing the algorithm, it's unclear.
The multi-dimensional array edges is effectively an "array of arrays." The for statement is extracting one element from edges at a time, and each element of edges is an int[].
So the first time through the loop, e will be {0, 1}. The second time it will be {1, 0}. The third time it will be {1, 2}. And so on.
The wikipedia page on the graph it's creating is http://en.wikipedia.org/wiki/Petersen_graph.
From the look of it, edges in the graph are represented by the Vertex.successors collection, and the edges array is used to construct the graph, using the first index as the from node and the second index as the to node for each edge.
This would also explain why each pair is followed by its opposite, eg {0,1}, {1,0}, as the Peterson Graph is undirected, so connections between nodes must be represented in both directions.

Categories