Determine whether rows in 2D array are unique - java

I'm trying to create an algorithm which determines whether or not all of the rows in a 2D array of integers are unique (i.e. disjoint). Currently, I have a brute force algorithm which checks each value in each row to each value in the other rows, but I'd like to speed this up. Is there some kind of divide and conquer method to handle this? I have found some semi-solutions for this in single arrays and lists, but not in 2d arrays.

If you want to check whether there are two rows that contain the same number, you can put all the numbers along with numbers of rows that they belong to into one long list. Then sort this list which will make all the identical numbers stand next to each other. Than you can easily determine for each cluster of identical numbers whether they originally belonged to the same row or not.
If your table is n × m, the algorithm will run in O(nm × (log(n) + log(m))).

To test whether any two rows are disjoint**, make two sets (like java sets that reject duplicates and do so in almost O(1) time), one for each row and count the elements of each.
The two rows are disjoint if:
count(rowASet) + count(rowBSet) == count( union(rowASet, rowBSet) )
This suggests an algorithm for a 2D array where a rows are successively added (as sets) to a running total set. The count of the total set is measured before and after the addition of each row's set. If that count increases by the size of the row set just added, then the row just added is disjoint from those added so far.
**See the conversation with #CandiedOrange. I'm taking "disjoint row" to mean a row that contains no element found in any other row, but might itself contain repeated elements internally.

EDIT: my answer was slow and stupid. Or to put it more kindly, it was doing unnecessary work because it computed which two rows intersect instead of whether or not any two rows intersect.
After I posted I thought of 2 faster algorithms but they turned out to be Danylo Mysak's answer and the "running total set" danh hinted at.
I would still like to benchmark these different approaches.

If you are allowed to use java collections consider using java's HashSet. It was designed for things like this:
areDisjoint() inspired by http://www.geeksforgeeks.org/check-two-given-sets-disjoint/
import java.util.*;
public static void main (String[] args)
{
int[][] twoD = {{3,3,3},{4,4,4},{5,5,5}};
if ( disjointRows(twoD) )
{
System.out.println("Mutually disjoint rows");
}
else
{
System.out.println("Some element duplicated in other row");
}
}
public static boolean disjointRows(int[][] twoD)
{
// -- Copy 2D array into data structure -- //
ArrayList<HashSet<Integer>> rows = new ArrayList<HashSet<Integer>>();
for (int[] row : twoD)
{
HashSet<Integer> hs = new HashSet<Integer>();
for (int elem : row)
{
hs.add(elem);
}
rows.add( hs );
}
// Above is O = r*c time just as it would be to copy the 2D array.
// or you can express it as O(n^2)
// -- Mutual disjoint rows test -- //
// Compare every combination of rows
for (int y=1; y< rows.size(); y++)
{
for (int x=0; x<y; x++)
{
//TODO remove debugging code
System.out.print(areDisjoint( rows.get(x), rows.get(y) ) );
System.out.print("=");
System.out.print("(" + x + "," + y + ") ");
if (! areDisjoint( rows.get(x), rows.get(y) ) )
{
return false;
}
}
System.out.println("");
}
return true;
//Above is O = r(r-1)/2 * c
//or you can express it as O(n^3)
}
static boolean areDisjoint(Set<Integer> set1, Set<Integer> set2)
{
//set1 must not contain anything in set2
for (int i : set2)
{
if ( set1.contains(i) )
return false;
}
return true;
// Above is c or O(n) because contains lookup is O(1)
}
Output:
// true=(0,1)
// true=(0,2) true=(1,2)
// Mutually disjoint rows
I can't tell if this is better than your "brute force" solution since you didn't post it.
I can tell from a big O notation perspective this is neck and neck with japreiss's solution. We're both at O(n^3). This solution uses more memory because it copies the 2D array rather than mutate it. When performance is equal I strongly urge you to pick your algorithm based on readability. I admit mine is longer. I took the time to comment it.
See also: Is a Java hashmap really O(1)?
// If each row is to be disjoint from all other rows then
// then testing them all against each other would produce
// this truth table.
//
// 0 1 2
// |----|----|----|
// 0 | F | T | T |
// |----|----|----|
// 1 | T | F | T |
// |----|----|----|
// 2 | T | T | F |
// |----|----|----|
//
// Testing a row against it self can be ignored as can
// tests that simply transpose the input rows. Leaving us with
//
// 0 1 2
// |
// 0 |
// |----|
// 1 | T |
// |----|----|
// 2 | T | T |
// |----|----|
//
// So long as that's true, the rows are mutually disjoint

Related

Sorting A Two-Dimensional (2D) Array as a whole without Row/Column Order

I was working on a Two Dimensional Array and I need to sort it in as a whole and not as in One Row/One Column Sort.
Say,
8 7 9 3
-2 0 4 5
1 3 6 -4
It should look like this,
-2 -1 0 1
2 3 4 5
6 7 8 9
I did It.
Took Two-Days to come up with an algorithm. Its not a perfect algorithm and maybe not even well optimized. But It Works.
Explanation
The Idea Is To get The Minimum Value From A Certain Element (say 0,0) To the End Of Array (i.e. a.length, a[0].length) and swapping it with the Certain Element.
Here I have created a Diagram to better understand the logic.
We Do this Till We Reach The Last Element and Voila! We Have a Sorted 2D-Array.
Code [JAVA]
Now, Come's the fun Part from where I lost Two Brain Cells. The Code.
What I have done, Is To Create a function which returns me the minimum value In a Array.
The Function takes two parameter's which is the Starting Element Index i.e.(i,j) from which its supposed to run a loop to end and return the minimum value with its index in a List.
//Helper Method
//row = Row Of Element To Began Loop From
//column = Column Of Element To Began Loop From.
List get_min(int row,int column)
{
List<Integer> l = new ArrayList<Integer>(); // List To Return with the output.
int mn=a[row][column], mni=0,mnj=0;
//mni= The Row Of Minimum Element
// mnj = The Column Of Minimum Element
for(int i=row;i<a.length;i++)
{
for(int j=column;j<a[0].length;j++)
{
if(mn>a[i][j])
{
mni = i;
mnj = j;
mn=a[i][j];
}
}
column=0; // This needs to be zero, just so the next time Row Updates The Loop doesn't began from the 2nd Element But 0.
}
l.add(mn); l.add(mni); l.add(mnj);
return l;
}
Now We Have A List With Three Values, The Minimum Element, The Minimum Element Row, The Minimum Element Column. We Can Now Build A Simple, Swap Function with the Use of Helper Method Above.
void sort_array()
{
for(int i=0; i<a.length;i++)
{
for(int j=0;j<a[0].length;j++)
{
List<Integer> l = get_min(i, j); // List with Minimum Value As In Step 1,Step 2, Step 3
if(a[i][j]>l.get(0)) // Check To Prevent Last Value Replacing The First Element
{
//Simple Swap
int t = a[i][j];
a[i][j] = l.get(0);
a[l.get(1)][l.get(2)] = t;
}
}
}
}
Voila Now You Have An Sorted 2D-Array. Enjoy with the data.

Allocating N tonnes of food in K rooms with M capacity

I found this problem online:
You have N tonnes of food and K rooms to store them into. Every room has a capacity of M. In how many ways can you distribute the food in the rooms, so that every room has at least 1 ton of food.
My approach was to recursively find all possible variations that satisfy the conditions of the problem. I start with an array of size K, initialized to 1. Then I keep adding 1 to every element of the array and recursively check whether the new array satisfies the condition. However, the recursion tree gets too large too quickly and the program takes too long for slightly higher values of N, K and M.
What would be a more efficient algorithm to achieve this task? Are there any optimizations to be done to the existing algorithm implementation?
This is my implementation:
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
public class Main {
// keeping track of valid variations, disregarding duplicates
public static HashSet<String> solutions = new HashSet<>();
// calculating sum of each variation
public static int sum(int[] array) {
int sum = 0;
for (int i : array) {
sum += i;
}
return sum;
}
public static void distributionsRecursive(int food, int rooms, int roomCapacity, int[] variation, int sum) {
// if all food has been allocated
if (sum == food) {
// add solution to solutions
solutions.add(Arrays.toString(variation));
return;
}
// keep adding 1 to every index in current variation
for (int i = 0; i < rooms; i++) {
// create new array for every recursive call
int[] tempVariation = Arrays.copyOf(variation, variation.length);
// if element is equal to room capacity, can't add any more in it
if (tempVariation[i] == roomCapacity) {
continue;
} else {
tempVariation[i]++;
sum = sum(tempVariation);
// recursively call function on new variation
distributionsRecursive(food, rooms, roomCapacity, tempVariation, sum);
}
}
return;
}
public static int possibleDistributions(int food, int rooms, int roomCapacity) {
int[] variation = new int[rooms];
// start from all 1, keep going till all food is allocated
Arrays.fill(variation, 1);
distributionsRecursive(food, rooms, roomCapacity, variation, rooms);
return solutions.size();
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int food = in.nextInt();
int rooms = in.nextInt();
int roomCapacity = in.nextInt();
int total = possibleDistributions(food, rooms, roomCapacity);
System.out.println(total);
in.close();
}
}
Yes, your recursion tree will become large if you do this in a naive manner. Let's say you have 10 tonnes and 3 rooms, and M=2. One valid arrangement is [2,3,5]. But you also have [2,5,3], [3,2,5], [3,5,2], [5,2,3], and [5,3,2]. So for every valid grouping of numbers, there are actually K! permutations.
A possibly better way to approach this problem would be to determine how many ways you can make K numbers (minimum M and maximum N) add up to N. Start by making the first number as large as possible, which would be N-(M*(K-1)). In my example, that would be:
10 - 2*(3-1) = 6
Giving the answer [6,2,2].
You can then build an algorithm to adjust the numbers to come up with valid combinations by "moving" values from left to right. In my example, you'd have:
6,2,2
5,3,2
4,4,2
4,3,3
You avoid the seemingly infinite recursion by ensuring that values are decreasing from left to right. For example, in the above you'd never have [3,4,3].
If you really want all valid arrangements, you can generate the permutations for each of the above combinations. I suspect that's not necessary, though.
I think that should be enough to get you started towards a good solution.
One solution would be to compute the result for k rooms from the result for k - 1 rooms.
I've simplified the problem a bit in allowing to store 0 tonnes in a room. If we have to store at least 1 we can just subtract this in advance and reduce the capacity of rooms by 1.
So we define a function calc: (Int,Int) => List[Int] that computes for a number of rooms and a capacity a list of numbers of combinations. The first entry contains the number of combinations we get for storing 0 , the next entry when storing 1 and so on.
We can easily compute this function for one room. So calc(1,m) gives us a list of ones up to the mth element and then it only contains zeros.
For a larger k we can define this function recursively. We just calculate calc(k - 1, m) and then build the new list by summing up prefixes of the old list. E.g. if we want to store 5 tons, we can store all 5 in the first room and 0 in the following rooms, or 4 in the first and 1 in the following and so on. So we have to sum up the combinations for 0 to 5 for the rest of the rooms.
As we have a maximal capacity we might have to leave out some of the combinations, i.e. if the room only has capacity 3 we must not count the combinations for storing 0 and 1 tons in the rest of the rooms.
I've implemented this approach in Scala. I've used streams (i.e. infinite Lists) but as you know the maximal amount of elements you need this is not necessary.
The time complexity of the approach should be O(k*n^2)
def calc(rooms: Int, capacity: Int): Stream[Long] =
if(rooms == 1) {
Stream.from(0).map(x => if(x <= capacity) 1L else 0L)
} else {
val rest = calc(rooms - 1, capacity)
Stream.from(0).map(x => rest.take(x+1).drop(Math.max(0,x - capacity)).sum)
}
You can try it here:
http://goo.gl/tVgflI
(I've replaced the Long by BigInt there to make it work for larger numbers)
First tip, remove distributionsRecursive and don't build up a list of solutions. The list of all solutions is a huge data set. Just produce a count.
That will let you turn possibleDistributions into a recursive function defined in terms of itself. The recursive step will be, possibleDistributions(food, rooms, roomCapacity) = sum from i = 1 to roomCapacity of possibleDistributions(food - i, rooms - 1, roomCapacity).
You will save a lot of memory, but still have your underlying performance problem. However with a pure recursive function you can now fix that with https://en.wikipedia.org/wiki/Memoization.

Print all the combinations of elements in a 2D Matrix

Print all the combinations of elements in matrix of size m * n.
Sample Example:
1 3 5
2 6 7
Expected Output:
2 , 1
2 , 3
2 , 5
6 , 1
6 , 3
6 , 5
7 , 1
7 , 3
7 , 5
Rules:
- Every combination starts from bottom of matrix and proceeds towards top. It may switch columns though.
- Every combination should have number of elements equal to number of rows.
- A combination can't have an element from the same row present twice.
I never could figure the solution out for general case. I can use 3 loops. But I want to understand the recursive solution. I use Java.
Here's a non-recursive way to solve this problem (it's not all that pretty, but it works for your input). I know you were interested in recursion, but I don't have anything like that for you at the moment. Generally, I avoid recursion due to the size of problems I work with (constant heap space errors due to the size of the recursive stack even when -Xmx60G). Hope this helps.
private static List<int[]> combos;
public static void main(String[] args){
combos = new ArrayList<int[]>();
generate(new int[][]{{1,3,5},{2,6,7}});
for(int[] s : combos){
System.out.println(java.util.Arrays.toString(s));
}
}
private static void generate(int[][] elements) {
int rows = elements.length;
int[] elementsIndex = new int[rows];
int[] elementsTotals = new int[rows];
java.util.Arrays.fill(elementsTotals, elements[0].length);
int curIdx = 0;
int[] c = new int[rows];
while(true){
while(curIdx >= 0){
if(curIdx == rows) {
addCombo(c);
curIdx--;
}
if(elementsIndex[curIdx] == elementsTotals[curIdx]){
elementsIndex[curIdx] = 0;
curIdx--;
} else break;
}
if(curIdx < 0) break;
// toggle order:
// bottom up: elements[rows-curIdx-1][elementsIndex[curIdx]++]
// top down: elements[curIdx][elementsIndex[curIdx]++]
c[curIdx] = elements[rows-curIdx-1][elementsIndex[curIdx]++];
curIdx++;
}
}
private static void addCombo(int[] c){
int[] a = new int[c.length];
System.arraycopy(c, 0, a, 0, c.length);
combos.add(a);
}
A recursive solution would look something like this:
printPermutations(String head, Matrix m)
if m is empty print head and return
else for each item in last row of m
printPermutations(head + item, m - bottom row)
here "head" is all the work we've done so far. In the body of a recursive method, there have to be at least two alternatives, one that outputs a result and ends the recursion, and one that goes deeper. For the deeper alternative, we transfer the selected element to head, remove the bottom row since we can't pick more than one item from any row, and do it again.
Done well, a recursive solution is often simpler and cleaner than using loops. On the other hand, recursion tends to use more memory

Finding all Logical Combinations of a Set

I am writing to ask if anyone knows how to go about this. I do not need the code, I would just like the logic behind doing this. So I have a set {A,B,C,D,E}. Now I want to find all combinations of and or OR operators amongst the values in the set.
Some examples below.
A and B and C and D and E
A and B and C and D or E
A and B and C or D and E
From what I know there is 2^n-1 possibilities in the case above. So in the specific example above we would have 8 combinations.
In addition to the Above the values in the set can have two possibilities. For simplicities sake lets say A can be True or False. Likewise B,C,D and E. So what we would potentially have is something like the following :
A=True and B=True and C=True and D=True and E=True
A=True and B=True and C=True and D=True and E=False
A=True and B=True and C=True and D=True or E=True
and so on. So taking this into account we would have 2^(2 * n-1) combinations. So in our specific example above again we would have 16 combinations for a set of 4.
Is there an algorithm that already does this? If not would anyone have some logic to implement this in Java
Thanks,
I think you're saying you want to enumerate (perhaps print) all the distinct expressions of the forms you have described, for some set size n. Since each one can be characterized by a set of flags (=True vs =False at positions 1 ... n, and And vs Or at positions 1 ... n - 1), you can represent each expression as an integer, with each flag corresponding to one (binary) bit. If n has a value for which you could hope to explicitly enumerate all the possibilities, such an integer will be well within the range of a Java long. For comfortably being able to enumerate all the possibilities, such an integer will be within the range of a Java int.
One way to proceed, therefore, would be to write a method to decode in-range integers into expressions according to their bit patterns. You can then iterate over all the appropriate integers (i.e. 0 ... (1 << (2 * n)) - 1), and decode each one into the corresponding expression.
If you have to get possible combination of five boolean values, you can do one thing -
Iterate a loop from zero to binary value "11111".
In each iteration you will get a unique combination of 0 and 1.
Convert 1 to true and 0 to false.
I hope below code will be helpful :
import java.util.ArrayList;
public class Test{
public static void main (String[] args)
{
ArrayList<boolean[]> result = new ArrayList<boolean[]>();
int max_num = Integer.parseInt("11111", 2);
for(int i=max_num; i>=0; i--)
{
String val = String.format("%5s", Integer.toBinaryString(i)).replace(' ', '0');
boolean[] arr = new boolean[5];
char[] charArray = val.toCharArray();
for(int j=0; j<charArray.length;j++)
{
if(charArray[j]=='1')
{
arr[j]=true;
}
else
{
arr[j]=false;
}
}
result.add(arr);
arr=null;
val=null;
}
for(int i=0;i<result.size();i++)
{
for(boolean b: result.get(i))
{
System.out.print(b+" ");
}
System.out.println();
}
}
}
To change the variable count :
Replace same count of 1 with "11111". e.g. if variable count is 6, it should be "111111"
Change "%5s" accordingly. e.g. if variable count is 6, it should be "%6s".
Initialize array "arr" with same count.

All possible combinations of strings from char array in Java

I'm having a school project for Java and I'm assigned too. Now I'm having an issue with a part of the project which I can't figure out.
The application must generate all possible word combinations (can be verified via a dictionary) from a two-dimensional char array (char[][] board). The board is dynamic as the user can choose the scale: 4x4, 5x5, 4x5, 5x4, 4x6, ... So I guess a nested loop wouldn't be approriate here, correct me if I'm wrong. Words must be generated horizontally, verticaly and diagonally. Example of a 4x4 board:
| u | a | u | s |
| n | n | i | i |
| a | o | e | b |
| e | u | e | z |
Code was completely wrong.
Another idea may be to brute force every possible path on the board and then try those saved paths to verify whether it's a word or not.
Thanks in advance!
One way to solve this is:
for each path on the board
if corresponding word in dictionary
print it
To find all paths, you could adapt any graph traversal algorithm.
Now this will be really slow, because there are a great many paths of a board that size (for a board with n cells, we can have at most n * 4 ^ (n - 1) paths, so for a 5 by 5 board, you'd have something like 25 * 2 ^ 50 ~= 10^16 paths.
One way to improve on this is to interleave traversing the graph and checking the dictionary, aborting if the current path's word is not a prefix of a dictionary word:
class Board {
char[][] ch;
boolean[][] visited;
Trie dictionary;
void find() {
StringBuilder prefix = new StringBuilder();
for (int x = 0; x < maxx; x++) {
for (int y = 0; y < maxy; y++) {
walk(x, y, prefix);
}
}
}
void walk(int x, int y, StringBuilder prefix) {
if (!visited[x][y]) {
visited[x][y] = true;
prefix.append(ch[x][y]);
if (dictionary.hasPrefix(prefix)) {
if (dictionary.contains(prefix)) {
System.out.println(prefix);
}
int firstX = Math.max(0, x - 1);
int lastX = Math.min(maxx, x + 1);
int firstY = Math.max(0, y - 1);
int lastY = Math.min(maxy, y + 1);
for (int ax = firstX; ax <= lastX; ax++) {
for (int ay = firstY; ay <= lastY; ay++) {
walk(ax, ay, prefix);
}
}
}
prefix.setLength(prefix.length() - 1);
visited[x][y] = false;
}
}
As you can see, the method walk invokes itself. This technique is known as recursion.
That leaves the matter of finding a data structure for the dictionary that supports efficient prefix queries. The best such data structure is a Trie. Alas, the JDK does not contain an implementation, but fortunately, writing one isn't hard.
Note: The code in this answer has not been tested.
A fairly straightforward way of conceptualizing this is to apply a breadth-first search (BFS) approach to each position (or depth-first, depending upon which tweaks you might later want to make). This would give you all possible letter combinations, up to a level of characters equal to the max depth of the search. Depending on your requirements, such as the longest allowed word, max running time, and if a dictionary is provided via a data structure or file, this may be the key part.
Or, you may need to optimize quite a bit more. If so, consider how you might expedite either a BFS or DFS. What if you did a DFS, but knew three characters in that no word starts with "zzz"? You could shave a lot of time off by not having to traverse all conceivable orderings. To look words up effectively, you might need to make further adjustments. But I'd start with Java's built-in functionality (String.startsWith() comes to mind in this instance), measure performance (perhaps with a limited max word length), and then optimize when and where it's needed.
Start by turning rows , columns and diagonals to Strings, using a simple repetitive method. Then , I would turn it into a StringBuilder or in order to check which words are real and eliminate those which aren't directly from the StringBuilder. then , just print it to a String.There are a lot of useful tools to eliminate or replace words in java.

Categories