Transitive closure and Warshall algorithm - java

My input matrix is following:
0 1 1 0
0 0 1 0
1 0 0 1
0 0 0 0
My code for the Warshall's algorithm is following:
int V = A.length;
for(int k = 0; k < V; k++) {
for(int i = 0; i < V; i++) {
for(int j = 0; j < V; j++) {
A[i][j] = A[i][j] == 1 || A[i][k] == 1 && A[k][j] == 1 ? 1 : 0;
}
}
}
The formula for the transitive closure of a matrix is (matrix)^2 + (matrix). Following the formula, I get this as an answer:
1 1 1 1
1 0 1 1
1 1 1 1
0 0 0 0
Using the piece of code I mentioned before, i get this as an answer:
1 1 1 1
1 1 1 1
1 1 1 1
0 0 0 0
So, my question is following, which one of the answers is right and is the algorithm working the correct way?

The formula for the transitive closure of a matrix is (matrix)^2 +
(matrix). Following the formula, I get this as an answer:
Not exactly, you are looking for the transitive closure of (matrix)^2 + matrix, this is the formula for a single step - not for the entire solution.
This means, you need to apply it again, and then you get in a second iteration:
1 1 1 1
1 1 1 1
1 1 1 1
0 0 0 0
(Since there is a path from 0 to 1)
The third iteration will apply the same matrix, which means this is the transitive closure.
So, from this test case, it seems the algorithm is corret.
That said, the line A[i][j] = A[i][j] == 1 || A[i][k] == 1 && A[k][j] == 1 ? 1 : 0; is quite unreadable, imho - don't be afraid to break it or at least add some parentheses

Related

Need help reading a text file

So far I have developed a program that uses an adjacency matrix to build a graph using linked implementation.
I'm stuck on how I can read a text file containing an adjacency matrix, and using that data instead of manually inputting the adjacency matrix.
For example, a text file containing the following:
4
0 1 1 0
1 1 1 1
1 0 0 0
1 1 0 1
6
0 1 0 1 1 0
1 0 0 1 1 0
0 0 1 0 0 1
0 0 0 0 1 0
1 0 0 0 0 0
0 0 1 0 0 1
3
0 1 1
1 0 1
1 1 0
You can use this method to read matrix data from file. This method returns a 2d array of bytes containing zeroes and ones.
public static void main(String[] args) throws IOException {
byte[][] matrix = getMatrixFromFile("matrix.txt");
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + ((j + 1) == matrix[i].length ? "" : " "));
}
System.out.println();
}
}
public static byte[][] getMatrixFromFile(String filename) throws IOException {
List<String> lines = Files.readAllLines(Paths.get(filename));
int size = Byte.parseByte(lines.get(0));
byte[][] matrix = new byte[size][size];
for (int i = 1; i < lines.size(); i++) {
String[] nums = lines.get(i).split(" ");
for (int j = 0; j < nums.length; j++) {
matrix[i - 1][j] = Byte.parseByte(nums[j]);
}
}
return matrix;
}
Here I am assuming the file will contain data for one matrix, like following, but my code can easily be extended to read data for multiple matrices and return a list of 2d byte array.
4
0 1 1 0
1 1 1 1
1 0 0 0
1 1 0 1

set value for random element on matrix

I'm trying to generate a 8 by 8 matrix. Each element of matrix needs to have a value of 1 except one element on each column which is set as 0, that one element is chosen by generating a random int between 0-7.
What I get when I run the code:
1 1 1 1 1 1 1 1
1 1 1 0 1 1 1 1
1 1 0 1 1 1 1 1
1 0 1 1 1 1 1 1
1 0 1 1 1 1 1 1
1 0 0 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 0 1 1
My matrix should look like this:
1 1 1 1 1 1 1 1
1 1 0 1 1 1 1 1
1 1 1 1 1 0 1 0
0 1 1 1 1 1 1 1
1 1 1 0 1 1 0 1
1 0 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 0 1 1 1
code
for (int[] row: grid)
Arrays.fill(row, 1);
for (int i=0; i<grid.length; i++) {
int j = getRandom();
grid[i][j] = 0;
}
// print matrix
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++)
System.out.format("%2s%2d%2s", " ", Main.grid[i][j], " ");
System.out.println();
}
In your nested loop, both initialization and nulling of cells are in the innermost loop. This will cause both to run once per cell, but nulling is only done once per column.
If we change the order that the cells are initialized in from row after row to column after column, we can move the nulling logic out to the outermost loop.
for (int c = 0; c < 8; c++) {
for (int r = 0; r < 8; r++) {
Main.grid[r][c] = 1;
}
Main.grid[getRandom()][c] = 0; // assuming your getRandom() is within range
}
Firstly let's make the matrix all 1s:
//fill however you like
int[][] matrix = IntStream.range(0, 8).mapToObj(i
-> IntStream.range(0, 8).map(i -> 1).toArray());
Then, based on your question, it seems like you want a unique row per column to have a zero. So just shuffle your column indexes:
List<Integer> rows = IntStream.range(0, 8).collect(Collectors.toList());
Collections.shuffle(rows); //random rows per 0-8 column
AtomicInteger column = new AtomicInteger();
//iterate columns, and select random row
rows.forEach(i -> matrix[i][column.getAndIncrement()] = 0);
This'll disperse the random 0s to be unique per row (and column), and there's not really any RNG involved so it's O(n)
First of all, use the Arrays.fill api, it will make your code much cleaner and concise.
int[][] matrix = new int[m][n];
// Fill each row with 1
for (int[] row: matrix)
Arrays.fill(row, 1);
Then, for each row, pick a column number at random and insert '0' thereby replacing the 1.
for(int i=0; i<matrix.length; i++) {
int j = Math.Random(0,matrix[0].length); // Or any other api for random number generation
matrix[i][j] = 0;
}

Finding all the common substrings of given two strings

I have come across a problem statement to find the all the common sub-strings between the given two sub-strings such a way that in every case you have to print the longest sub-string. The problem statement is as follows:
Write a program to find the common substrings between the two given strings. However, do not include substrings that are contained within longer common substrings.
For example, given the input strings eatsleepnightxyz and eatsleepabcxyz, the results should be:
eatsleep (due to eatsleepnightxyz eatsleepabcxyz)
xyz (due to eatsleepnightxyz eatsleepabcxyz)
a (due to eatsleepnightxyz eatsleepabcxyz)
t (due to eatsleepnightxyz eatsleepabcxyz)
However, the result set should not include e from
eatsleepnightxyz eatsleepabcxyz, because both es are already contained in the eatsleep mentioned above. Nor should you include ea, eat, ats, etc., as those are also all covered by eatsleep.
In this, you don't have to make use of String utility methods like: contains, indexOf, StringTokenizer, split and replace.
My Algorithm is as follows: I am starting with brute force and will switch to more optimized solution when I improve my basic understanding.
For String S1:
Find all the substrings of S1 of all the lengths
While doing so: Check if it is also a substring of
S2.
Attempt to figure out the time complexity of my approach.
Let the two given strings be n1-String and n2-String
The number of substrings of S1 is clearly n1(n1+1)/2.
But we have got to find the average length a substring of S1.
Let’s say it is m. We’ll find m separately.
Time Complexity to check whether an m-String is a substring of an
n-String is O(n*m).
Now, we are checking for each m-String is a substring of S2,
which is an n2-String.
This, as we have seen above, is an O(n2 m) algorithm.
The time required by the overall algorithm then is
Tn=(Number of substrings in S1) * (average substring lengthtime for character comparison procedure)
By performing certain calculations, I came to conclusion that the
time complexity is O(n3 m2)
Now, our job is to find m in terms of n1.
Attempt to find m in terms of n1.
Tn = (n)(1) + (n-1)(2) + (n-2)(3) + ..... + (2)(n-1) + (1)(n)
where Tn is the sum of lengths of all the substrings.
Average will be the division of this sum by the total number of Substrings produced.
This, simply is a summation and division problem whose solution is as follows O(n)
Therefore...
Running time of my algorithm is O(n^5).
With this in mind I wrote the following code:
package pack.common.substrings;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class FindCommon2 {
public static final Set<String> commonSubstrings = new LinkedHashSet<String>();
public static void main(String[] args) {
printCommonSubstrings("neerajisgreat", "neerajisnotgreat");
System.out.println(commonSubstrings);
}
public static void printCommonSubstrings(String s1, String s2) {
for (int i = 0; i < s1.length();) {
List<String> list = new ArrayList<String>();
for (int j = i; j < s1.length(); j++) {
String subStr = s1.substring(i, j + 1);
if (isSubstring(subStr, s2)) {
list.add(subStr);
}
}
if (!list.isEmpty()) {
String s = list.get(list.size() - 1);
commonSubstrings.add(s);
i += s.length();
}
}
}
public static boolean isSubstring(String s1, String s2) {
boolean isSubstring = true;
int strLen = s2.length();
int strToCheckLen = s1.length();
if (strToCheckLen > strLen) {
isSubstring = false;
} else {
for (int i = 0; i <= (strLen - strToCheckLen); i++) {
int index = i;
int startingIndex = i;
for (int j = 0; j < strToCheckLen; j++) {
if (!(s1.charAt(j) == s2.charAt(index))) {
break;
} else {
index++;
}
}
if ((index - startingIndex) < strToCheckLen) {
isSubstring = false;
} else {
isSubstring = true;
break;
}
}
}
return isSubstring;
}
}
Explanation for my code:
printCommonSubstrings: Finds all the substrings of S1 and
checks if it is also a substring of
S2.
isSubstring : As the name suggests, it checks if the given string
is a substring of the other string.
Issue: Given the inputs
S1 = “neerajisgreat”;
S2 = “neerajisnotgreat”
S3 = “rajeatneerajisnotgreat”
In case of S1 and S2, the output should be: neerajis and great
but in case of S1 and S3, the output should have been:
neerajis, raj, great, eat but still I am getting neerajis and great as output. I need to figure this out.
How should I design my code?
You would be better off with a proper algorithm for the task rather than a brute-force approach. Wikipedia describes two common solutions to the longest common substring problem: suffix-tree and dynamic-programming.
The dynamic programming solution takes O(n m) time and O(n m) space. This is pretty much a straightforward Java translation of the Wikipedia pseudocode for the longest common substring:
public static Set<String> longestCommonSubstrings(String s, String t) {
int[][] table = new int[s.length()][t.length()];
int longest = 0;
Set<String> result = new HashSet<>();
for (int i = 0; i < s.length(); i++) {
for (int j = 0; j < t.length(); j++) {
if (s.charAt(i) != t.charAt(j)) {
continue;
}
table[i][j] = (i == 0 || j == 0) ? 1
: 1 + table[i - 1][j - 1];
if (table[i][j] > longest) {
longest = table[i][j];
result.clear();
}
if (table[i][j] == longest) {
result.add(s.substring(i - longest + 1, i + 1));
}
}
}
return result;
}
Now, you want all of the common substrings, not just the longest. You can enhance this algorithm to include shorter results. Let's examine the table for the example inputs eatsleepnightxyz and eatsleepabcxyz:
e a t s l e e p a b c x y z
e 1 0 0 0 0 1 1 0 0 0 0 0 0 0
a 0 2 0 0 0 0 0 0 1 0 0 0 0 0
t 0 0 3 0 0 0 0 0 0 0 0 0 0 0
s 0 0 0 4 0 0 0 0 0 0 0 0 0 0
l 0 0 0 0 5 0 0 0 0 0 0 0 0 0
e 1 0 0 0 0 6 1 0 0 0 0 0 0 0
e 1 0 0 0 0 1 7 0 0 0 0 0 0 0
p 0 0 0 0 0 0 0 8 0 0 0 0 0 0
n 0 0 0 0 0 0 0 0 0 0 0 0 0 0
i 0 0 0 0 0 0 0 0 0 0 0 0 0 0
g 0 0 0 0 0 0 0 0 0 0 0 0 0 0
h 0 0 0 0 0 0 0 0 0 0 0 0 0 0
t 0 0 1 0 0 0 0 0 0 0 0 0 0 0
x 0 0 0 0 0 0 0 0 0 0 0 1 0 0
y 0 0 0 0 0 0 0 0 0 0 0 0 2 0
z 0 0 0 0 0 0 0 0 0 0 0 0 0 3
The eatsleep result is obvious: that's the 12345678 diagonal streak at the top-left.
The xyz result is the 123 diagonal at the bottom-right.
The a result is indicated by the 1 near the top (second row, ninth column).
The t result is indicated by the 1 near the bottom left.
What about the other 1s at the left, the top, and next to the 6 and 7? Those don't count because they appear within the rectangle formed by the 12345678 diagonal — in other words, they are already covered by eatsleep.
I recommend doing one pass doing nothing but building the table. Then, make a second pass, iterating backwards from the bottom-right, to gather the result set.
Typically this type of substring matching is done with the assistance of a separate data structure called a Trie (pronounced try). The specific variant that best suits this problem is a suffix tree. Your first step should be to take your inputs and build a suffix tree. Then you'll need to use the suffix tree to determine the longest common substring, which is a good exercise.

add or subtract 1 from a row in a 2D array

So I got this 2D Array that is a 5x5 array and I have to subtract or add 1 to one of the rows that the user chooses to change. All is fine when the user inputs to change the first row, but with the higher rows, for example 2, it adds more than 1.
The array values are
1 -2 1 0 0
-1 0 4 2 0
0 -4 1 -1 0
0 1 -1 -1 -2
0 -3 1 -1 0
And the method I used to add 1 is the following
public static void plusRow (int i){
for(int row = 0; row < board.length; row++){
int[] rows = board[i];
for(int col = 0; col < board.length; col++){
rows[col] = rows[col] + 1;
System.out.print(board[row][col] + " ");
}
System.out.println("");
}
}
My output value for example with 2 comes out like this
1 -2 1 0 0
1 2 6 4 2
0 -4 1 -1 0
0 1 -1 -1 -2
0 -3 1 -1 0
When it should be
1 -2 1 0 0
0 1 5 3 1
0 -4 1 -1 0
0 1 -1 -1 -2
0 -3 1 -1 0
The problem is that your nested for loop runs as many times as the function input int "i"
Your algorithm is very inefficient- you don't need to do a nested loop here. Break your ouput and your math into 2 different loops.
for(int j =0; j<boards[i].length; j++){
boards[i][j] += 1;
}
Then write a double loop to ouput board. In fact, that should be a separate function

Add extra number beside array

i want setting an array and below is my code
public static void setArray()
{
int i = 5;
int j = 5;
int testarray[][] = new int[i][j];
for(int x = 0;x<i;x++)
{
for(int y=0;y<j;y++)
{
System.out.print("0 ");
}
System.out.println("");
}
}
the result is something like this:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
if i want to put a number/alphabet beside to let the user know which column, how can i do that ?
Expected Result:
====================
1 2 3 4 5
A|0 0 0 0 0
B|0 0 0 0 0
C|0 0 0 0 0
D|0 0 0 0 0
E|0 0 0 0 0
You need another initial for-loop to print the numbers, then you need to add another print statement within your second for-loop to print the letter for each row:
System.out.print(" ");
for (int x = 0; x < i; x++) { // this prints the numbers on the first row
System.out.print(" " + x);
}
System.out.println();
for (int x = 0; x < i; x++) {
System.out.print((char) ('A' + x) + "|"); // this prints the letters
for (int y = 0; y < j; y++) {
System.out.print("0 ");
}
System.out.println("");
}
0 1 2 3 4
A|0 0 0 0 0
B|0 0 0 0 0
C|0 0 0 0 0
D|0 0 0 0 0
E|0 0 0 0 0
You need to print 1, 2, 3, 4, 5 .. column number of times and print A, B, C, D .. till you reach the number of rows. Try coding it yourself, it's not that difficult (I don't want to provide a ready-made code)

Categories

Resources