Counting Connections in a m*n matrix - java

I am trying to find the expected output to the below program..But I am getting the error
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at programbasics.CountingConnections.count(CountingConnections.java:7)
at programbasics.CountingConnections.main(CountingConnections.java:26)
My question is about a matrix m*n. The elements in matrix are populated with values 1 and 0.
1 indicates in establishing connection and 0 indicates Not establishing connection.
we need to connect the available adjacent positions vertically, horizontally and diagonally and count the number of distinct connections established
My piece of code is
package programbasics;
class CountingConnections
{
static int count(int a[][], int i, int j) {
int rows = a.length;
int cols = a[0].length;
if(a[i][j] == 0) return 0;
if (i == rows - 1 && j == cols - 1)
return a[i][j];
else if (i == rows - 1)
return a[i][j + 1];
else if (j == cols - 1)
return a[i + 1][j];
else if (a[i][j] == 1)
return count(a, i + 1, j) + count(a, i, j + 1);
else
return 0;
}
public static void main(String[]args)
{
int a[][] = {{1,0,0,1},
{0,1,1,1},
{1,0,0,1}};
int i = 3;
int j = 4;
System.out.println(count(a, i, j));;
}
}
The expected output is 8. Like the positions are connected as follows
1)(0,0) -> (1,1)
2)(2,0) -> (1,1)
.
.
.
.
8) (0,3) -> (1,3)
It fails to get the expected output 8.
public static int count(int[][] a) {
int[][] paths = new int[a.length][a[0].length];
if ((paths[0][0] = a[0][0]) == 0) {
return 0;
}
for (int c = 1; c < a[0].length; c++) {
paths[0][c] = a[0][c] * paths[0][c - 1];
}
for (int r = 1; r < a.length; r++)
{
paths[r][0] = a[r][0] * paths[r - 1][0];
for (int c = 1; c < a[r].length; c++)
{
paths[r][c] = a[r][c] * (paths[r - 1][c] + paths[r][c - 1]);
}
}
return paths[a.length - 1][a[0].length - 1];
}

public static int count(int[][] a, int m, int n) {
int count = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (a[i][j] == 1) {
if (i - 1 >= 0 && j - 1 >= 0 && a[i - 1][j - 1] == 1) {
count = count + 1;
}
if (i - 1 >= 0 && a[i - 1][j] == 1) {
count = count + 1;
}
if (i - 1 >= 0 && j + 1 < n && a[i - 1][j + 1] == 1) {
count = count + 1;
}
if (j + 1 < n && a[i][j + 1] == 1) {
count = count + 1;
}
}
}
}
return count;
}

You call if(a[i][j] == 0) in your code where you pass 3 as i and 4 as j. However Array's are zero indexed, so when you try to call a[3][4] you are trying to call
0 1 2 3 4
0 {1, 0, 0, 1}
1 {0, 1, 1, 1}
2 {1, 0, 0, 1}
3 X
4
The index where the X is. Clearly this is not a valid index in your Array.
Also your method at different points calls a[i + 1][j] and a[i][j + 1] which means that you will have to take this in account when making sure the code stays in bounds.
As to your actual method your logic seems a bit off. if(a[i][j] == 0) return 0; will return 0 and stop the recursion and return 0 without checking to see if there are any more connections. Your logic should be something more like this:
Start at 0,1.
If the index is a 1
Look one index to the right, one down and to the right (The diagonal) down one, and down one and to the left (The second diagonal).
If any of the numbers at those index's are 1's then up the counter.
Continue to iterate through the matrix, but keep in mind that you are checking one row down and over, so you will only loop until less than length -1 for for both the row and column. Also make sure that you are starting at index a[i][1] as you will be needing to check a[a+1][j-1] and if j == 0 you will be trying to call a[a+1][-1] which will cause another index out of bounds

private int countConnections(int[][] a, int rows, int columns) {
//cartesian plane coordinates around a point
final int[] x = {1, 1, 1, -1, -1, -1, 0, 0};
final int[] y = {1, -1, 0, 1, -1, 0, 1, -1};
int count = 0;
boolean[][] visited = new boolean[rows][columns];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
for (int k = 0; k < 8; k++) {
int l = i + x[k];
int m = j + y[k];
//check for connections only if the given cell has value 1
if (a[i][j] == 1 && canVisit(l, m, rows, columns, visited) && a[l][m] == 1) {
count++;
}
}
visited[i][j] = true;
}
}
return count;
}
private boolean canVisit(int i, int j, int rows, int columns, boolean [][] visited) {
return i < rows && j < columns && i >= 0 && j >= 0 && !visited[i][j];
}
Check all the 8 cells around a cell whose cell value is 1 and when traversed mark it as visited.

Related

How to print all the diagonals of a matrix in Java

I'm trying to figure out how to print an NxN matrix diagonally. Right now I can print the left to right diagonal but not the right to left.
So let's say the matrix is:
1 2 3
4 5 6
7 8 9
Now I can print left to right:
1
4 2
7 5 3
8 6
9
But I want also to print right to left:
3
6 2
9 5 1
8 4
7
Here is the code for left to right:
public static void printLeftToRightDiagonal(int[][] matrix) {
int length = matrix.length;
int diagonalLines = (length + length) - 1;
int itemsInDiagonal = 0;
int midPoint = (diagonalLines / 2) + 1;
for (int i = 1; i <= diagonalLines; i++) {
int rowIndex;
int columnIndex;
if (i <= midPoint) {
itemsInDiagonal++;
for (int j = 0; j < itemsInDiagonal; j++) {
rowIndex = (i - j) - 1;
columnIndex = j;
System.out.print(matrix[rowIndex][columnIndex] + " ");
}
} else {
itemsInDiagonal--;
for (int j = 0; j < itemsInDiagonal; j++) {
rowIndex = (length - 1) - j;
columnIndex = (i - length) + j;
System.out.print(matrix[rowIndex][columnIndex] + " ");
}
}
System.out.println();
}
}
I tried to figure out the pattern but I was left without ideas
The problem can be divided into two tasks:
print one reverse diagonal starting from a generic matrix[i, j] element, basically decrementing i and j by 1 in every cycle if both i and j are >= 0, otherwise ending the cycle.
identifying the starting matrix[i, j] elements and print the reverse diagonal starting from them.
The first rule is equivalent to write a method like below:
//example for matrix[2, 2] it will print 9 5 1
private static void printReverseDiagonal(int[][] matrix, int i, int j) {
System.out.print(matrix[i][j]);
for (int row = i - 1, column = j - 1; row >= 0 && column >= 0; --row, --column) {
System.out.print(" " + matrix[row][column]);
}
System.out.println();
}
The second rule is equivalent to write one cycle iterating over elements matrix[0, n - 1], matrix[1, n - 1] ... matrix[n - 1, n - 1] and another one iterating over elements matrix[n - 2, n - 1], matrix[n - 3, n - 1] .... matrix[0, n - 1] like below:
public static void printRightToLeftDiagonal(int[][] matrix) {
int n = matrix.length;
int j = n - 1;
for (int i = 0; i < n; ++i) {
printReverseDiagonal(matrix, i, j);
}
int i = n - 1;
for(j = n - 2; j >= 0; --j) {
printReverseDiagonal(matrix, i, j);
}
}
Combining the two functions you obtain your expected result.

Median of 2-D Matrix (Minesweeper)

I am trying to solve this assignment but not able to figure out the logic on how to get the median here.
Question:- Find the median of a 2D-Matrix. (which is a Minesweeper game's result). Only horizontal and vertical values (1's) are counted. (Please click on the link for sample results).
Question
Solution:-
public static int findMedian2(int[][] matrix)
{
int size = 0;
for(int i = 0; i < matrix.length; i++)
{
for(int j = 0; j < matrix[i].length; j++)
{
if(matrix[i][j] == 1)
{
size++;
dfs(matrix, i, j);
}
}
}
return size;
}
private static void dfs(int[][] grid, int r, int c)
{
if(r < 0 || r >= grid.length || c < 0 || c >= grid[r].length || grid[r][c] == 0)
return;
grid[r][c] = 0;
dfs(grid, r - 1, c);
dfs(grid, r + 1, c);
dfs(grid, r, c - 1);
dfs(grid, r, c + 1);
}
So far I am able get the size. The size does not really give the right answer here, how do I achieve the median? I am new to matrix related problems. Any help would be greatly appreciated.
Update:-
Based on #Mike'Pomax'Kamermans's input I could come up with this:-
static int count;
static List<Integer> list = new ArrayList<Integer>();
public static int findMedian(int[][] matrix)
{
count = 0;
for (int i = 0; i < matrix.length; i++)
{
for (int j = 0; j < matrix[i].length; j++)
{
if (matrix[i][j] == 1)
{
dfs(matrix, i, j);
if (count != 0 && count != 1)
{
list.add(count);
}
count = 0;
}
}
}
// convert list to array
int[] array = list.stream().mapToInt(i -> i).toArray();
return findMedian(array);
}
private static void dfs(int[][] grid, int r, int c)
{
if(r < 0 || r >= grid.length || c < 0 || c >= grid[r].length || grid[r][c] == 0)
return;
grid[r][c] = 0;
dfs(grid, r - 1, c);
dfs(grid, r + 1, c);
dfs(grid, r, c - 1);
dfs(grid, r, c + 1);
count++;
}
/* Median of Unsorted Array to match the results */
private static int findMedian(int[] a)
{
// check for even case
if (a.length % 2 != 0)
{
return a[a.length / 2];
}
return (a[(a.length - 1) / 2] + a[a.length / 2]) / 2;
}
Will this be the correct way to calculate median for this question?

Finding the count of common array sequencce

I am trying to the length of the longest sequence of numbers shared by two arrays. Given the following two arrays:
int [] a = {1, 2, 3, 4, 6, 8,};
int [] b = {2, 1, 2, 3, 5, 6,};
The result should be 3 as the the longest common sequence between the two is{1, 2, 3}.
The numbers must be in a sequence for the program to consider to count it.
I have thought about it and wrote a small beginning however, I am not sure how to approach this
public static int longestSharedSequence(int[] arr, int[] arr2){
int start = 0;
for(int i = 0; i < arr.length; i++){
for(int j = 0; j < arr2.length; j++){
int n = 0;
while(arr[i + n] == arr2[j + n]){
n++;
if(((i + n) >= arr.length) || ((j + n) >= arr2.length)){
break;
}
}
}
That is a very good start that you have. All you need to do is have some way of keeping track of the best n value that you have encountered. So at the start of the method, declare int maxN = 0. Then, after the while loop within the two for loops, check if n (the current matching sequence length) is greater than maxN (the longest matching sequence length encountered so far). If so, update maxN to the value of n.
Since you also want the matching elements to be in sequential order, you will need to check that the elements in the two arrays not only match, but that they are also 1 greater than the previous element in each array.
Putting these together gives the following code:
public static int longestSharedSequence(int[] arr, int[] arr2) {
int maxN = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr2.length; j++) {
int n = 0;
// Check that elements match and that they are either the
// first element in the sequence that is currently being
// compared or that they are 1 greater than the previous
// element
while (arr[i + n] == arr2[j + n]
&& (n == 0 || arr[i + n] == arr[i + n - 1] + 1)) {
n++;
if (i + n >= arr.length || j + n >= arr2.length) {
break;
}
}
// If we found a longer sequence than the previous longest,
// update maxN
if (n > maxN) {
maxN = n;
}
}
}
return maxN;
}
I didn't think of anything smarter than the path you were already on:
import java.util.Arrays;
import java.util.Random;
public class MaxSeq {
public static void main(String... args) {
int[] a = new int[10000];
int[] b = new int[10000];
final Random r = new Random();
Arrays.parallelSetAll(a, i -> r.nextInt(100));
Arrays.parallelSetAll(b, i -> r.nextInt(100));
System.out.println(longestSharedSequence(a, b));
}
private static int longestSharedSequence(final int[] arr, final int[] arr2) {
int max = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr2.length; j++) {
int n = 0;
while ((i + n) < arr.length
&& (j + n) < arr2.length
&& arr[i + n] == arr2[j + n]) {
n++;
}
max = Math.max(max, n);
}
}
return max;
}
}
see: https://en.wikipedia.org/wiki/Longest_common_subsequence_problem

Faster way to find neighbors indexes

I'm creating a minesweeper game and I really need a fast and Efficient way of calculating the neighbors of a mine, Actually im storing my tiles in an Arraylist so I can use them in a gridview, so the position is lineal but the rendering will be a matrix n*n. I have a way to do it but I think someone can have a more efficient way.
What I want to achieve:
0 1 1 1
0 1 * 1
0 1 1 1
0 0 0 0
So given that matrix having the indexes in a lineal List the position should be the following:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
So I need an efficient way of obtaining 2, 3, 4, 6, 8, 10, 11, 12 giving the index 7.
Code to generate bombs:
public void plantMines(){
Random rand = new Random();
//Used set so we dont get duplicates
Set<Integer> mineCoords = new LinkedHashSet<>(mDifficulty.mines);
//First we randomly select all coordenates
while (mineCoords.size() < mDifficulty.mines){
Integer coord = rand.nextInt(mListCap) + 1;
mineCoords.add(coord);
}
//Now we can set the mines accordingly
for (Integer coord: mineCoords){
mTiles.get(coord).setMine(true);
}
}
Actual code to find neighbors:
for (int row = 0; row < ROW_SIZE; row++) {
for (int col = 0; col < COL_SIZE; col++) {
int neighbourBombSize = 0;
// TOP ROW
if ((row-1) >= 0 && (col-1) >= 0) {
if (getTile(row-1, col-1).hasBomb()) {
neighbourBombSize++;
}
}
if ((row-1) >= 0) {
if (getTile(row-1, col).hasBomb()) {
neighbourBombSize++;
}
}
if ((row-1) >= 0 && (col+1) < COL_SIZE) {
if (getTile(row-1, col+1).hasBomb()) {
neighbourBombSize++;
}
}
// SAME ROW
if ((col-1) >= 0) {
if (getTile(row, col-1).hasBomb()) {
neighbourBombSize++;
}
}
if ((col+1) < COL_SIZE) {
if (getTile(row, col+1).hasBomb()) {
neighbourBombSize++;
}
}
// BOTTOM ROW
if ((row+1) < ROW_SIZE && (col-1) >= 0) {
if (getTile(row+1, col-1).hasBomb()) {
neighbourBombSize++;
}
}
if ((row+1) < ROW_SIZE) {
if (getTile(row+1, col).hasBomb()) {
neighbourBombSize++;
}
}
if ((row+1) < ROW_SIZE && (col+1) < COL_SIZE) {
if (getTile(row+1, col+1).hasBomb()) {
neighbourBombSize++;
}
}
getTile(row, col).setNeighbourBombSize(neighbourBombSize);
}
}
Help will be appreciated, thanks.
WARNING : I've take your code as starting point, but your index start a 1, but in java array index start at 0, so it may not work.
I would do something like that :
int neighbourBombSize = 0;
// Compute currentCell row / col
int currentCellCol = ((currentCellIndex - 1) % COL_SIZE) + 1;
int currentCellRow = ((currentCellIndex - 1) / COL_SIZE) + 1;
System.out.println("Neighbors of " + currentCellIndex + " (" + currentCellRow + ", " + currentCellCol + ")");
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
if (x == 0 && y == 0) {
continue; // Current cell index
}
int neighborCol = currentCellCol + y;
int neighborRow = currentCellRow + x;
if (neighborCol > 0 && neighborRow > 0 && neighborCol <= COL_SIZE && neighborRow <= ROW_SIZE ) {
int computedNeighborIndex = neighborCol + ((neighborRow - 1) * COL_SIZE);
if (getTile(neighborRow , neighborCol ).hasBomb()) {
neighbourBombSize++;
}
}
}
}
You can see a running example (computing neighbors index for all case) here : Running example
Are you planning to write the whole game referring to cells using this 1-based linear index? If so, you will want to isolate the conversion to and from coordinates. Otherwise you will eventually mess up somewhere.
Try something like this:
class Board {
final int rows;
final int cols;
Board(int cols, int rows) {
this.rows = rows;
this.cols = cols;
}
int col(int index) {
assert index > 0 && index <= rows * cols;
return (index - 1) % cols; // -1 because you are using 1-based indexing.
}
int row(int index) {
assert index > 0 && index <= rows * cols;
return (index - 1) / cols;
}
int index(int x, int y) {
assert x >= 0 && x < cols && y >= 0 && y < rows;
return y * cols + x + 1;
}
int[] neighbors(int point) {
int x = col(point);
int y = row(point);
int[] result = new int[8];
int cnt = 0;
// go over possible neighbors and collect valid ones
for (int ny = max(y - 1, 0); ny < min(y + 2, rows); ny++) {
for (int nx = max(x - 1, 0); nx < min(x + 2, cols); nx++) {
if (nx != x || ny != y) {
result[cnt++] = index(nx, ny);
}
}
}
return Arrays.copyOf(result, cnt);
}
}
Board brd = new Board(4, 4);
int colOf7 = brd.col(7); // 2 (0-based from left)
int rowOf7 = brd.row(7); // 1 (0-based from top)
int[] neighborsOf7 = brd.neighbors(7); // [2, 3, 4, 6, 8, 10, 11, 12]
int index = brd.index(2,1); // 7 (1-based linear index)

Traversing a 2D array matrix diagonally from bottom left to upper right

I have a 3x4 matrix represented by a 2D array:
. 0 1 2 3
0 a c f i
1 b e h k
2 d g j l
and my approach to traverse the diagonal slice was to treat each slice as a sum, like this:
a = (0+0) = 0
b,c = (0+1),(1+0) = 1
d,e,f = (0+2),(1+1),(2+0) = 2
g,h,i = (1+2),(2+1),(3+0) = 3
j, k = (2+2),(3+1) = 4
l = (3+2) = 5
However, my code right now prints it in the opposite way that I want it to, which is from upper right to bottom left.
Current Output is:
acbfedihgkjl
Desired Output is:
abcdefghijkl
for (int sum = 0; sum <= numRows + numColumns - 2; sum++) {
for (int i = 0; i < numRows; i++) {
int j = sum - i;
if ((i >= 0 && i < numRows) && (j >= 0 && j < numColumns)) {
System.out.print(array[i][j]);
}
}
}
Can somebody point me in the right direction on how to fix my code to get the output that I want?
While it isn't very pretty, I think this will do it:
int i = 0;
int j = 0;
while (true) {
System.out.println("" + array[i][j]);
--i;
++j;
if (i < 0) {
if (j == numCols)
break;
i = Math.min(j, numRows - 1);
j = Math.max(j - numCols + 2, 0);
} else if (j >= numCols) {
if (i == numRows - 2)
break;
i = numRows - 1;
j = Math.max(j + 2 - numCols + i, 0);
}
}
int i = 0;
int j = 0;
int n = 0;
int x = 3;
int y = 4;
int newSize = Math.max(x,y) * Math.max(x,y);
while(n < newSize){
if(i <= x && j <= y)
System.out.println(array[i][j]);
n++;
if(i == 0) {
i = n:
j = 0;
} else {
--i;
++j;
}
}

Categories

Resources