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.
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.
Good evening, I have an array in java with n integer numbers. I want to check if there is a subset of size k of the entries that satisfies the condition:
The sum of those k entries is a multiple of m.
How may I do this as efficiently as possible? There are n!/k!(n-k)! subsets that I need to check.
You can use dynamic programming. The state is (prefix length, sum modulo m, number of elements in a subset). Transitions are obvious: we either add one more number(increasing the number of elements in a subset and computing new sum modulo m), or we just increase prefix lenght(not adding the current number). If you just need a yes/no answer, you can store only the last layer of values and apply bit optimizations to compute transitions faster. The time complexity is O(n * m * k), or about n * m * k / 64 operations with bit optimizations. The space complexity is O(m * k). It looks feasible for a few thousands of elements. By bit optimizations I mean using things like bitset in C++ that can perform an operation on a group of bits at the same time using bitwise operations.
I don't like this solution, but it may work for your needs
public boolean containsSubset( int[] a , int currentIndex, int currentSum, int depth, int divsor, int maxDepth){
//you could make a, maxDepth, and divisor static as well
//If maxDepthis equal to depth, then our subset has k elements, in addition the sum of
//elements must be divisible by out divsor, m
//If this condition is satisafied, then there exists a subset of size k whose sum is divisible by m
if(depth==maxDepth&¤tSum%divsor==0)
return true;
//If the depth is greater than or equal maxDepth, our subset has more than k elements, thus
//adding more elements can not satisfy the necessary conditions
//additionally we know that if it contains k elements and is divisible by m, it would've satisafied the above condition.
if(depth>=maxdepth)
return false;
//boolean to be returned, initialized to false because we have not found any sets yet
boolean ret = false;
//iterate through all remaining elements of our array
for (int i = currentIndex+1; i < a.length; i++){
//this may be an optimization or this line
//for (int i = currentIndex+1; i < a.length-maxDepth+depth; i++){
//by recursing, we add a[i] to our set we then use an or operation on all our subsets that could
//be constructed from the numbers we have so far so that if any of them satisfy our condition (return true)
//then the value of the variable ret will be true
ret |= containsSubset(a,i,currentSum+a[i],depth+1,divisor, maxDepth);
} //end for
//return the variable storing whether any sets of numbers that could be constructed from the numbers so far.
return ret;
}
Then invoke this method as such
//this invokes our method with "no numbers added to our subset so far" so it will try adding
// all combinations of other elements to determine if the condition is satisfied.
boolean answer = containsSubset(myArray,-1,0,0,m,k);
EDIT:
You could probably optimize this by taking everything modulo (%) m and deleting repeats. For examples with large values of n and/or k, but small values of m, this could be a pretty big optimization.
EDIT 2:
The above optimization I listed isn't helpful. You may need the repeats to get the correct information. My bad.
Happy Coding! Let me know if you have any questions!
If numbers have lower and upper bounds, it might be better to:
Iterate all multiples of n where lower_bound * k < multiple < upper_bound * k
Check if there is a subset with sum multiple in the array (see Subset Sum problem) using dynamic programming.
Complexity is O(k^2 * (lower_bound + upper_bound)^2). This approach can be optimized further, I believe with careful thinking.
Otherwise you can find all subsets of size k. Complexity is O(n!). Using backtracking (pseudocode-ish):
function find_subsets(array, k, index, current_subset):
if current_subset.size = k:
add current_subset to your solutions list
return
if index = array.size:
return
number := array[index]
add number to current_subset
find_subsets(array, k, index + 1, current_subset)
remove number from current_subset
find_subsets(array, k, index + 1, current_subset)
Let's say that you have an arbitrarily large sized two-dimensional array with an even amount of items in it. Let's also assume for clarity that you can only choose between two things to put as a given item in the array. How would you go about putting a random choice at a given index in the array but once the array is filled you have an even split among the two choices?
If there are any answers with code, Java is preferred but other languages are fine as well.
You could basically think about it in the opposite way. Rather than deciding for a given index, which value to put in it, you could select n/2 elements from the array and place the first value in them. Then place the 2nd value in the other n/2.
A 2-D A[M,N] array can be mapped to a vector V[M*N] (you can use a row-major or a column-major order to do the mapping).
Start with a vector V[M*N]. Fill its first half with the first choice, and the second half of the array with the second choice object. Run a Fisher-Yates shuffle, and convert the shuffled array to a 2-D array. The array is now filled with elements that are evenly split among the two choices, and the choices at each particular index are random.
The below creates a List<T> the size of the area of the matrix, and fills it half with the first choice (spaces[0]) and half with the second (spaces[1]). Afterward, it applies a shuffle (namely Fisher-Yates, via Collections.shuffle) and begins to fill the matrix with these values.
static <T> void fill(final T[][] matrix, final T... space) {
final int w = matrix.length;
final int h = matrix[0].length;
final int area = w * h;
final List<T> sample = new ArrayList<T>(area);
final int half = area >> 1;
sample.addAll(Collections.nCopies(half, space[0]));
sample.addAll(Collections.nCopies(half, space[1]));
Collections.shuffle(sample);
final Iterator<T> cursor = sample.iterator();
for (int x = w - 1; x >= 0; --x) {
final T[] column = matrix[x];
for (int y = h - 1; y >= 0; --y) {
column[y] = cursor.next();
}
}
}
Pseudo-code:
int trues_remaining = size / 2;
int falses_remaining = size / 2;
while (trues_remaining + falses_remaining > 0)
{
if (trues_remaining > 0)
{
if (falses_remaining > 0)
array.push(getRandomBool());
else
array.push(true);
}
else
array.push(false);
}
Doesn't really scale to more than two values, though. How about:
assoc_array = { 1 = 4, 2 = 4, 3 = 4, 4 = 4 };
while (! assoc_array.isEmpty())
{
int index = rand(assoc_array.getNumberOfKeys());
int n = assoc_array.getKeyAtIndex(index);
array.push(n);
assoc_array[n]--;
if (assoc_array[n] <= 0) assoc_array.deleteKey(n);
}
EDIT: just noticed you asked for a two-dimensional array. Well it should be easy to adapt this approach to n-dimensional.
EDIT2: from your comment above, "school yard pick" is a great name for this.
It doesn't sound like your requirements for randomness are very strict, but I thought I'd contribute some more thoughts for anyone who may benefit from them.
You're basically asking for a pseudorandom binary sequence, and the most popular one I know of is the maximum length sequence. This uses a register of n bits along with a linear feedback shift register to define a periodic series of 1's and 0's that has a perfectly flat frequency spectrum. At least it is perfectly flat within certain bounds, determined by the sequence's period (2^n-1 bits).
What does that mean? Basically it means that the sequence is guaranteed to be maximally random across all shifts (and therefore frequencies) if its full length is used. When compared to an equal length sequence of numbers generated from a random number generator, it will contain MORE randomness per length than your typical randomly generated sequence.
It is for this reason that it is used to determine impulse functions in white noise analysis of systems, especially when experiment time is valuable and higher order cross effects are less important. Because the sequence is random relative to all shifts of itself, its auto-correlation is a perfect delta function (aside from qualifiers indicated above) so the stimulus does not contaminate the cross correlation between stimulus and response.
I don't really know what your application for this matrix is, but if it simply needs to "appear" random then this would do that very effectively. In terms of being balanced, 1's vs 0's, the sequence is guaranteed to have exactly one more 1 than 0. Therefore if you're trying to create a grid of 2^n, you would be guaranteed to get the correct result by tacking a 0 onto the end.
So an m-sequence is more random than anything you'll generate using a random number generator and it has a defined number of 0's and 1's. However, it doesn't allow for unqualified generation of 2d matrices of arbitrary size - only those where the total number of elements in the grid is a power of 2.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
In-place transposition of a matrix
Recently attended an Technical Written Interview. Came through the following question.
I have an array as say
testArray = {a1,a2,a3,...an,b1,b2,b3,....bn,c1,c2,c3,.....,cn}
I need to sort this array as `
testArray = {a1,b1,c1,a2,b2,c2,a3,b3,c3,.....,an,bn,cn}
Constraint is I should not use extra memory, should not use any inbuilt function.
Should write complete code, it can be in any language and can also use any data structure.
eg:
Input: {1,2,3,4,5,6,7,8,9}, n = 3
Output: {1,4,7,2,5,8,3,6,9}
I could not get any solution within the constraint, can anyone provide solution or suggestion?
This is just a matrix transpose operation. And there is even a problem and solution for in-place matrix transposition on Wikipedia.
No extra space is impossible, since you need to at least go through the array. O(1) additional memory is possible, with heavy penalty on the time complexity.
The solution is built on follow-the-cycle algorithm in the Wikipedia page: for each cell, we will find the cell with the smallest index in the cycle. If the cell with the smallest index is greater than or equal (>=) to the index of the current cell, we will perform chain swapping. Otherwise, we ignore the cell, since it has been swapped correctly. The (loosely analyzed) upper bound on time complexity can go as high as O((MN)2) (we go through M * N cells, and the cycle can only be as long as the total number of cells).
Impossibility
It is impossible to implement this algorithm without extra use of memory and an arbitrary length because you need a an iterator to traverse the list and that takes up space.
Finding the right indices to swap
For fixed lengths of the array and fixed n you can use a matrix transpose algorithm.
and in order to swap the elements y
The algorithm you are looking for is a matrix transpose algorithm.
so you have to swap every element exactly once iterating through it.
http://en.wikipedia.org/wiki/Transpose
basically you have to swap the m -th element in the n - th component with the n - th element in the m -th component. This can be done by a double loop.
m = length(array)/n;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
{
index_1 = i * m + j;
index_2 = j * m + i
swap(index_1, index_2);
}
Note: For fixed m and n this loop can be completely unrolled and therefore m, i, j can be replaced by a constant.
Swaping without Memory consumption
In order to swap every element without using extra space you can use the XOR swap algorithm as pointed out in the comments:
X := X XOR Y
Y := Y XOR X
X := X XOR Y
The simplest way to swap two numbers (a and b) without using a temporary variable is like this:
b = b + a;
a = b - a;
b = b - a;
If you write that in a function, then you're part of the way there. How you keep track of which variable to swap within the arrays without using a temporary variable eludes me right now.
Bear in mind voters: he doesn't actually need to sort the array, just swap the right values.
Edit: this will work with large values in Java (and in C/C++ unless you turn on some very aggressive compiler optimisations - the behaviour is undefined but defaults to sane). The values will just wrap around.
Second edit - some (rather untested) code to flip the array around, with I think 4 integers over the memory limit. It's while technically massively unthreadsafe, but it would be parallelisable just because you only access each array location once at most:
static int[] a = {1,2,3,4,
5,6,7,8,
9,10,11,12,
13,14,15,16};
static int n = 4;
public static void main(String[] args)
{
for(int i = 0; i < a.length/n; i++) // 1 integer
for(int j = 0; j < n; j++) // 1 integer
if(j > i)
swap(i*n+j, j*n+i);
}
static void swap(int aPos, int bPos) // 2 integers
{
if(a[aPos] != a[bPos])
{
a[bPos] = a[aPos] + a[bPos];
a[aPos] = a[bPos] - a[aPos];
a[bPos] = a[bPos] - a[aPos];
}
}
Apologies if this misunderstands the question; I read it carefully and couldn't work out what was needed other than this.
Take a look at Quicksort algorithm
For more information about available algorithms, go to Sorting algorithm page.