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.
Related
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
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.
In chapter 8 of Cracking the Coding Interview, 6th Edition, there's a question for finding all the subsets, and this is the given solution:
Arraylist<Arraylist<Integer>> getSubsets(Arraylist<Integer> set, int index) {
Arraylist<Arraylist<Integer>> allsubsets;
if (set.size()== index) {//Base case - add empty set
allsubsets = new Arraylist<Arraylist<Integer>>();
allsubsets.add(new Arraylist<Integer>()); // Empty set
} else {
allsubsets = getSubsets(set, index+ 1);
int item = set.get(index);
Arraylist<Arraylist<Integer>> moresubsets = new Arraylist<Arraylist<Integer>>();
for (Arraylist<Integer> subset : allsubsets) {
Arraylist<Integer> newsubset = new Arraylist<Integer>();
newsubset.addAll(subset);
newsubset.add(item);
moresubsets.add(newsubset);
}
allsubsets.addAll(moresubsets);
}
return allsubsets;
}
To my understanding, I need to add the current element to all the subsets found for the previous element from the given set. I don't understand why the recursive call takes index+1 as a given parameter instead of index-1. Is this a typo or is my understanding incorrect?
The idea behind this particular recursive function seems to be that getSubsets(set, i) means "generate and return all subsets of the elements in the input list s from index i and forward." If you look at how the recursion works, it does so as follows:
If i == set.size(), then we're supposed to generate all subsets of the elements from index set.size() and forward. There aren't any elements here, so the only subset is the empty set.
Otherwise, notice that each subset of the elements of set, starting at index i, either include the ith element or they don't. The subsets that don't contain the ith element are precisely the subsets of set starting from position i + 1 and forward. The ones that do are formed by taking those subsets, then adding in the ith element to them.
So in that sense, the reason the recursion goes to index i + 1 rather than i - 1 is because the intuition is to look at subsets of elements starting from position i and going to the end.
You could alternatively write this function to list subsets from index 0 up through index i if you'd like and then step i downward toward 0. It's a perfectly reasonable way to do this and a great exercise to code it up yourself!
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.
am trying to create vector of Vectors(2d) in java like multidimensional array. then to assign values to specific position in that matrix like what we do using matrix[i][j] in 2D array
Any help.
My data in one Vector:
n = [a, b, c, d, e, f, g , h]
I want to create 2D Vector to represent
vector m =
a b c d
e f g h
You can create a 2D Vector using the following:
Vector<Vector<Integer>> vector2D = new Vector<Vector<Integer>>(10);
This will create a Vector of size 10 which will contain Vectors with Integer(Vector) values.
Before setting a value at a particular index, you need to create a Vector of Integer and set at the row position(2 in your case).
vector2D.add(2, new Vector<Integer>(10));
You can then set a value at the column index using the following syntax:
Vector<Integer> rowVector = vector2D.get(2);
rowVector.add(3, 5);
Here we first get the Vector of Integers (Vector) at index 2. Then add the value at the index 3 in the Vector of Integers(Vector).
Hope this explains.
For whatever reasons, SO bumped your question just a couple minutes ago. In 2021 you probably would not use Vector any more, but List. Actually both of them have subList(start,end) method (even in Java 7 what the link points to), so practically you would just loop over vector/list in row-sized steps and use this method.
Also, you might fancy using streams so instead of initializing the result variable in a separate line, the stream collector does that for you:
List<Integer> vector=Arrays.asList(1,2,3,4,5,6,7,8);
int rowSize=4;
List<List<Integer>> matrix=IntStream.range(0, vector.size()/rowSize)
.mapToObj(row->vector.subList(row*rowSize, (row+1)*rowSize))
.collect(Collectors.toList());
System.out.println(matrix);
will output [[1, 2, 3, 4], [5, 6, 7, 8]].
Also, as Vector can be constructed from List, after all you can do that too:
Vector<Integer> vector=new Vector<Integer>(Arrays.asList(1,2,3,4,5,6,7,8));
int rowSize=4;
Vector<Vector<Integer>> matrix=new Vector<Vector<Integer>>(
IntStream.range(0, vector.size()/rowSize)
.mapToObj(row->new Vector<Integer>(vector.subList(row*rowSize, (row+1)*rowSize)))
.collect(Collectors.toList()));
System.out.println(matrix);
And of course in the background both of them do pretty much the same as a for loop would have done:
Vector<Integer> vector=new Vector<Integer>(Arrays.asList(1,2,3,4,5,6,7,8));
int rowSize=4;
Vector<Vector<Integer>> matrix=new Vector<Vector<Integer>>();
for(int row=0;row<vector.size()/rowSize;row++)
matrix.add(new Vector<Integer>(vector.subList(row*rowSize, (row+1)*rowSize)));
System.out.println(matrix);