Pattern in a matrix with dot and hash - java

Find patterns in a given matrix.
I have a matrix with values '.' and '#'
Now I want to find count with the given pattern in the matrix :
a)
##
b)
#
#
For the above pattern, the cells if exist surrounding them should be '.'
I am able to create successful logic for it:
static int getMatches(String[] B, int m, int n) {
int count = 0;
boolean[][] flag = new boolean[m][n];
for (int i = 0; i < m; i++) {
String S = B[i];
for (int j = 0; j < n; j++) {
char c = S.charAt(j);
boolean valid = true;
if (c == '#' && flag[i][j] == false) {
if (j + 1 < n && S.charAt(j + 1) == '#' && flag[i][j + 1] == false) {
int[][] adj = { { 0, -1 }, { 0, 2 }, { -1, 0 }, { -1, 1 }, { 1, 0 }, { 1, 1 } };
valid = isValid(adj, i, j, m, n, B);
} else {
valid = false;
}
} else {
valid = false;
}
if (c == '#' && !valid && flag[i][j] == false) {
if (i + 1 < m && S.charAt(i + 1) == '#' && flag[i + 1][i] == false) {
int[][] adj = { { 0, -1 }, { 1, -1 }, { 1, 1 }, { 0, 1 }, { -1, 0 }, { 2, 0 } };
valid = isValid(adj, i, j, m, n, B);
} else {
valid = false;
}
}
flag[i][j] = true;
if (valid) {
count++;
}
}
}
return count;
}
static boolean isValid(int[][] adj, int i, int j, int m, int n, String[] B) {
for (int a = 0; a < adj.length; a++) {
int i1 = i + adj[a][0];
int j1 = j + adj[a][1];
if (i1 >= 0 && i1 < m) {
if (j1 >= 0 && j1 < n) {
char d = B[i1].charAt(j1);
if (d == '#') {
return false;
}
}
}
}
return true;
}
Now I want to change the pattern to 3 cells like this:
a)
###
b)
#
#
#
c)
##
#
d)
##
#
e)
#
##
f)
#
##
How to build logic for this? Is their a way to extend my above code or is there a better approach to solve this problem.

As far as I understand, the problem can be simplified to finding the adjacent # fields, and their area must match a certain number.
So I have created the following code:
public static int getMatches(String[] matrix, int m, int n, int patternArea) {
int count = 0;
for (int i = 0; i < m; i++) {
String row = matrix[i];
for (int j = 0; j < n; j++) {
char item = row.charAt(j);
if (item == '#' && countArea(matrix, i, j) + 1 == patternArea) {
count++;
}
}
}
return count;
}
private static int countArea( String[] matrix, final int i, final int j ) {
int area = 0;
setVisited(matrix, i,j);
if (matrix[Math.max(i-1, 0)].charAt(j) == '#') {
area += countArea(matrix, i-1, j) + 1;
}
if (matrix[Math.min(i+1, matrix.length-1)].charAt(j) == '#') {
area += countArea(matrix, i+1, j) + 1;
}
if (matrix[i].charAt(Math.max(j-1, 0)) == '#') {
area += countArea(matrix, i, j-1) + 1;
}
if (matrix[i].charAt(Math.min(j+1, matrix[0].length()-1)) == '#') {
area += countArea(matrix, i, j+1) + 1;
}
return area;
}
private static void setVisited( final String[] matrix, final int i, final int j ) {
char[] rowChars = matrix[i].toCharArray();
rowChars[j] = '0';
matrix[i] = String.valueOf(rowChars);
}
Explanation:
Find at least 1 # field
From that position, recursively find any adjacent # fields - countArea method
Always mark already visited fields - I chose 0, but any other char will do other than . and #
Finally, if the area is matching a given number (patternArea), increase count variable
This is working only, if you include all of the patterns for a certain number. Given your example, you did just that. In case you really want to do exact pattern matching, then this approach will not be useful for your case.

Shared solution should work with any matrix of any symbols and number of rows/columns
Let's assume next parameters that we'll have as our input:
Matrix is represented as two-dimensional array - matrix[r][c], where r - number of rows in matrix, c - number of columns in matrix
Matrix has all its cells filled with some symbols
Pattern is represented as two-dimensional array - arr[k][m], where k - number of rows in pattern, m - number of columns in pattern
Algorithm will iterate each column of each row in matrix
Pattern can potentially be present in cell[x][y] only if next conditions are met:
x + k <= r (there are enough of matrix rows below this one (including current row) to include number of pattern rows)
y + m <= c (there are enough of matrix columns right of this one (including current column) to include number of pattern columns)
Comparison of pattern to current matrix cells says that they are equal. Comparison in done based on next conditions:
if pattern character is null - continue comparison
if pattern character is equal to matrix character - continue comparison
if pattern character is not equal to matrix character - end comparison, pattern is not located in this cell
if all pattern symbols checked - pattern is found in given matrix cell
Result of comparison in represented in 0-based index pairs
Let's get to the code.
We will have next classes:
Pattern Rule - represents pattern to be found. please specify nulls manually to make actually 2-dimensional array of equal row/col count
private static final class PatternRule {
private final Character[][] pattern;
private final int rowCount;
private final int colCount;
private PatternRule(Character[][] pattern) {
this.pattern = pattern;
this.rowCount = pattern.length;
this.colCount = pattern[0].length;
}
public int getRowCount() {
return rowCount;
}
public int getColCount() {
return colCount;
}
public Character getCharacterAt(int row, int column) {
return pattern[row][column];
}
}
Found Pattern Location - class to represent found cells for pattern locations
private static final class FoundPatternLocation {
private final int rowIndex;
private final int colIndex;
private FoundPatternLocation(int rowIndex, int colIndex) {
this.rowIndex = rowIndex;
this.colIndex = colIndex;
}
#Override
public String toString() {
return "[" + rowIndex + "][" + colIndex + "]";
}
}
Matrix - class that creates matrix and performs search of pattern locations
private static final class Matrix {
private final Character[][] matrix;
private final int rowCount;
private final int colCount;
private Matrix(int rowCount, int colCount, Character[][] matrix) {
this.rowCount = rowCount;
this.colCount = colCount;
this.matrix = matrix;
}
public static Matrix createMatrix(int rowCount, int colCount, char[] matrixSymbols) {
Character[][] newMatrix = new Character[colCount][rowCount];
Random rand = new Random();
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
for (int colIndex = 0; colIndex < colCount; colIndex++) {
// select random char from allowed symbols
newMatrix[rowIndex][colIndex] = matrixSymbols[rand.nextInt(matrixSymbols.length)];
}
}
return new Matrix(rowCount, colCount, newMatrix);
}
public void printMatrix() {
System.out.println("---- Matrix -----");
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
List<String> rowValues = new ArrayList<>();
for (int colIndex = 0; colIndex < colCount; colIndex++) {
rowValues.add(String.valueOf(matrix[rowIndex][colIndex]));
}
String printableRowString = String.join(" ", rowValues);
System.out.println(printableRowString);
}
System.out.println("-----------------");
}
public List<FoundPatternLocation> findPatternLocations(PatternRule patternRule) {
List<FoundPatternLocation> actualPatternLocation = new ArrayList<>();
for (int rowNum = 0; rowNum < this.rowCount; rowNum++) {
for (int colNum = 0; colNum < this.colCount; colNum++) {
if (isPatternFittingToCurrentCell(rowNum, colNum, patternRule)) { // can pattern be located in this cell?
if (isPatternLocatedInCell(rowNum, colNum, patternRule)) { // is pattern actually located in this cell?
actualPatternLocation.add(new FoundPatternLocation(rowNum, colNum));
}
}
}
}
return actualPatternLocation;
}
private boolean isPatternFittingToCurrentCell(int matrixRowIndex, int matrixColIndex, PatternRule patternRule) {
int patternRowsCount = patternRule.getRowCount();
int patternColumnsCount = patternRule.getColCount();
int availableMatrixRowsForPattern = rowCount - matrixRowIndex;
int availableMatrixColsForPattern = colCount - matrixColIndex;
return patternRowsCount <= availableMatrixRowsForPattern && patternColumnsCount <= availableMatrixColsForPattern;
}
private boolean isPatternLocatedInCell(int rowNum, int colNum, PatternRule patternRule) {
int patternRowsCount = patternRule.getRowCount();
int patternColumnsCount = patternRule.getColCount();
for (int currentPatternRowIndex = 0; currentPatternRowIndex < patternRowsCount; currentPatternRowIndex++) {
for (int currentPatternColIndex = 0; currentPatternColIndex < patternColumnsCount; currentPatternColIndex++) {
int currentMatrixRowIndex = currentPatternRowIndex + rowNum;
int currentMatrixColIndex = currentPatternColIndex + colNum;
Character currentMatrixCharacter = matrix[currentMatrixRowIndex][currentMatrixColIndex];
Character currentPatternCharacter = patternRule.getCharacterAt(currentPatternRowIndex, currentPatternColIndex);
if (currentPatternCharacter == null) {
continue;
}
if (Objects.equals(currentMatrixCharacter, currentPatternCharacter)) {
continue;
}
return false;
}
}
return true;
}
}
Class to perform execution
public static void main(String[] args) {
int rowCount = 5;
int colCount = 5;
char[] matrixSymbols = new char[] {'✓', 'X'};
Matrix matrix = Matrix.createMatrix(rowCount, colCount, matrixSymbols);
matrix.printMatrix();
PatternRule patternRuleA = createPatternRuleA();
PatternRule patternRuleB = createPatternRuleB();
PatternRule patternRuleC = createPatternRuleC();
List<FoundPatternLocation> patternLocationsA = matrix.findPatternLocations(patternRuleA);
printPatternLocations(patternLocationsA, "Pattern A");
List<FoundPatternLocation> patternLocationsB = matrix.findPatternLocations(patternRuleB);
printPatternLocations(patternLocationsB, "Pattern B");
List<FoundPatternLocation> patternLocationsC = matrix.findPatternLocations(patternRuleC);
printPatternLocations(patternLocationsC, "Pattern C");
}
private static void printPatternLocations(List<FoundPatternLocation> patternLocations, String patternName) {
System.out.println("---- " + patternName + " ----");
String string = patternLocations.stream().map(FoundPatternLocation::toString).collect(Collectors.joining("; "));
System.out.println(string);
System.out.println("--------");
}
private static PatternRule createPatternRuleA() {
Character[][] chars = {
{'✓', '✓', '✓'}
};
return new PatternRule(chars);
}
private static PatternRule createPatternRuleB() {
Character[][] chars = {
{'✓'},
{'✓'},
{'✓'}
};
return new PatternRule(chars);
}
private static PatternRule createPatternRuleC() {
Character[][] chars = {
{'✓', '✓'},
{'✓', null}
};
return new PatternRule(chars);
}
Example of execution:
---- Matrix -----
✓ ✓ X ✓ X
✓ ✓ ✓ ✓ ✓
X X X X ✓
X ✓ X X ✓
X X ✓ ✓ ✓
-----------------
---- Pattern A ----
[1][0]; [1][1]; [1][2]; [4][2]
--------
---- Pattern B ----
[1][4]; [2][4]
--------
---- Pattern C ----
[0][0]
--------

Related

Building Tic-Tac-Toe Board and am stuck on an infinite loop. Any Suggestions?

I am trying to make the board display alternating X's and O's on each square of the board and am having trouble not being able to stop the program from infinitely printing on the first space and switching markers. First I will show the class:
public class Board {
int cellsize = 4;
int cellsperrow = 3;
int rowsize = cellsize * cellsperrow;
public final char[] marker = new char [] {'X'};
public String boardRep = "___|___|___\n___|___|___\n | | ";
public final char [] [] board = new char[cellsperrow][cellsperrow];
public Board(){
for(int R = 0; R < board.length; ++R){
for(int C = 0; C < board[R].length; ++C){
board[R][C] = ' ';
}
}
}
boolean IsEmpty(int row, int col){
return board[row][col] == ' ';
}
public boolean markBoard(char marker, int row, int col){
if(!IsEmpty(row,col) || !isInRangeIndex(row,col)) {
boardRep = boardRep.substring(0, row*rowsize) + boardRep.substring(row*rowsize,(row*rowsize) + (col*cellsize) + 1) + marker + boardRep.substring((row*rowsize) + (col*cellsize) + 2, boardRep.length());
return false;
}
board[row][col] = marker;
return true;
}
boolean isInRange(int V){
return V >= 0 && V <= 2;
}
boolean isInRangeIndex(int r, int c){
return isInRange(r) && isInRange(c);
}
}
This is the Main:
Board B = new Board();
char [] markers = {'X','O'};
int marker = 0;
int numRows = 3;
int numCols = 3;
for(int row = 0; row < numRows; ++row){
for(int col = 0; col < numCols; ++col){
while(true){
System.out.println(B.boardRep);
B.markBoard(markers[marker],row,col);
marker = (marker + 1) %markers.length;
System.out.println(B.boardRep);
}
}
}
}
}
Any suggestions are appreciated. Thank you! I apologize if this is not formatted right I am newer to this and have never used this website before.

How to solve two dimensional growth grid problem?

I was doing an assessment for job interview. One of the 3 problems that I had to solve in an hour was finding the maximal value in a grid where you traverse it and add 1 to the elements based on the coordinates given. I spent a little to much time on the second problem and only ended up with about 20 minutes for this one. I didn't finish it in time so it's bugging me.
I just want to make sure that the solution to the problem as I remember it is optimized.
The input is a String array of two int values and the dimension of the grid.
To illustrate, if the coordinates given are (3,2) (2,2) (1,3) then
[1][1][0]
[1][1][0]
[1][1][0]
[1][1][0]
[2][2][0]
[2][2][0]
[1][1][0]
[2][2][0]
[3][3][1]
and so on...
I believe the required result was the maximal value that is not in (1,1) and the number of times it exists in the grid.
This is the the solution I came up with. Is there any way to optimize it?
public static List<Integer> twoDimensions(String[] coordinates, int n) {
List<Integer> maxAndCount = new ArrayList<Integer>();
int[][] grid = new int[n][n];
int arrLength = coordinates.length;
int max = Integer.MIN_VALUE;
int count = 1;
for (int i = 0; i < arrLength; i++) {
String[] coors = coordinates[i].split(" ");
int row = Integer.parseInt(coors[0]);
int column = Integer.parseInt(coors[1]);
for (int j = 0; j < row; j++) {
for (int k = 0; k < column; k++) {
grid[j][k] += 1;
System.out.println("grid (" + j + "," + k + "): " + grid[j][k]);
if (!(j == 0 & k == 0) && grid[j][k] > max) {
max = grid[j][k];
count = 1;
} else if (grid[j][k] == max) {
count++;
}
}
}
}
maxAndCount.add(max);
maxAndCount.add(count);
return maxAndCount;
}
public static void main(String[] args) {
String[] coors = { "1 3", "2 4", "4 1", "3 2" };
System.out.println("The Max and count Are:" + twoDimensions(coors, 4).toString());
}
Other solution for exercise is. (erikdhv#gmail.com)
public static long countMax(List<String> upRight) {
// Write your code here
int xl = 1;
int yl = 1;
xl = Integer.parseInt(upRight.get(1).split(" ")[0]);
yl = Integer.parseInt(upRight.get(1).split(" ")[1]);
for (int i=0; i<upRight.size(); i++){
if (xl > Integer.parseInt(upRight.get((int) i).split(" ")[0]) ) xl = Integer.parseInt(upRight.get((int) i).split(" ")[0]);
if (yl > Integer.parseInt(upRight.get((int) i).split(" ")[1])) yl = Integer.parseInt(upRight.get((int) i).split(" ")[1]);
}
return (yl * xl);
}
This fails a few test cases I can think of, the value of XL should be on Index 0 not 1
Answer of erik fails for few test cases, just change int to long for xl and yl and boom... all test cases passed.
public static long twoDimensions(List<String> list, int n) {
long res = 0;
int rowCount =0,colCount=0;
for(int i=0;i<n;i++)
{
int row = list.get(i).charAt(0) - 48;
int col = list.get(i).charAt(2) - 48;
if(row > rowCount)
rowCount = row;
if(col >colCount)
colCount = col;
}
int tempArr[][] = new int[rowCount+1][colCount+1];
for(int i = 0;i<n;i++)
{
int row = list.get(i).charAt(0) - 48;
int col = list.get(i).charAt(2) - 48;
for(int j=row;j>=1;j--)
{
int m = j;
for(int k=1;k<=col;k++)
{
tempArr[m][k]= tempArr[m][k]+1;
if(tempArr[m][k]>res)
res = tempArr[m][k];
}
}
System.out.println("for row: "+row+" col: "+col);
for(int j = 0;j<=rowCount;j++)
{
for(int k=0;k<=colCount;k++)
{
System.out.print(""+tempArr[j][k]);
}
System.out.println("");
}
System.out.println("");
}
return res;
}

Is there a test case scenario in which my program will fail?

Problem : You have L, a list containing some digits (0 to 9). Write a function solution(L) which finds the largest number that can be made from some or all of these digits and is divisible by 3. If it is not possible to make such a number, return 0 as the solution. L will contain anywhere from 1 to 9 digits. The same digit may appear multiple times in the list, but each element in the list may only be used once.
Test Cases :
Input:
Solution.solution({3, 1, 4, 1})
Output: 4311
Input:
Solution.solution({3, 1, 4, 1, 5, 9})
Output: 94311
My Program :
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.stream.IntStream;
public class Solution {
static ArrayList<Integer> al = new ArrayList<Integer>();
static ArrayList<Integer> largest = new ArrayList<Integer>();
static int o = 1;
static int po = 0;
static void combinations(String[] digits, String[] data, int start, int end, int index, int r)
{
if (index == r)
{
String temp = "0";
for (int j = 0; j < r; j++)
{
temp = temp + data[j];
// System.out.print(data[j]);
}
Integer d = Integer.parseInt(temp);
al.add(d);
// System.out.println(al);
}
for (int i = start; i <= end && ((end - i + 1) >= (r - index)); i++)
{
data[index] = digits[i];
combinations(digits, data, i + 1, end, index + 1, r);
}
}
static void printCombinations(String[] sequence, int N)
{
String[] data = new String[N];
for (int r = 0; r < sequence.length; r++)
combinations(sequence, data, 0, N - 1, 0, r);
}
static String[] convert(int[] x)
{
String c[] = new String[x.length];
for(int i=0; i < x.length; i++)
{
Integer k = x[i];
if(k==0)
{
o = o * 10;
continue;
}
c[i] = k.toString();
}
// System.out.println(o);
c = Arrays.stream(c).filter(s -> (s != null && s.length() > 0)).toArray(String[]::new);
po = c.length;
// System.out.println("Come"+ Arrays.asList(c));
return c;
}
public static int solution(int[] l) {
if(l.length==0)
return 0;
if(IntStream.of(l).sum()%3==0)
{
String x = "";
Arrays.sort(l);
for (int i = l.length - 1; i >= 0; i--) {
x = x + l[i];
}
return Integer.parseInt(x);
}
printCombinations(convert(l),po);
al.sort(Comparator.reverseOrder());
al.remove(al.size()-1);
al.removeIf( num -> num%3!=0);
if(al.isEmpty())
return 0;
for(int i=0; i< al.size(); i++)
{
Integer n = al.get(i);
printMaxNum(n);
}
// System.out.println(al);
// System.out.println(largest);
return largest.get(0)*o;
}
static void printMaxNum(int num)
{
// hashed array to store count of digits
int count[] = new int[10];
// Converting given number to string
String str = Integer.toString(num);
// Updating the count array
for(int i=0; i < str.length(); i++)
count[str.charAt(i)-'0']++;
// result is to store the final number
int result = 0, multiplier = 1;
// Traversing the count array
// to calculate the maximum number
for (int i = 0; i <= 9; i++)
{
while (count[i] > 0)
{
result = result + (i * multiplier);
count[i]--;
multiplier = multiplier * 10;
}
}
// return the result
largest.add(result);
}
public static void main(String[] args) {
System.out.println(solution(new int[]{9,8,2,3}));
}
}
My Code passes both given test cases and 3 other hidden test cases except one. I tried all possible input combinations but couldn't get to the exact failure. The return type by default is given as int and therefore they would not pass values which give output that does not fit in int. Any other scenario where my code fails?

Stuck on recursion algorithm

I got a question about recursion for an entry exam of a job, but I failed to do it within 2 hours. I am very curious about how to do this after the pre-exam but I cannot work out a solution.
You can imagine there is a coin pusher with size n*m (2D array).
Each operation (moving up or down or left or right) will throw away one row or one column of coins
The question requires me to find the shortest possible moves that remains k coins at last. If it is impossible to remain k coins at last, then return -1
I stuck on how to determine the next move when there is more than one operation that having the same maximum number of coins (same value to be thrown away)
I believe that I need to calculate recursively that simulates all future possible moves to determine the current move operation.
But I do not know how to implement this algorithm, can anyone help?
Thank you!
Question :
There is a rectangular chessboard containing N‘M cells. each of
which either has one coin or nothing.
You can move all the coins together in one direction (such as up,
down, left, and right), but each time you can move these coins by
only one cell.
If any coins fall out of the chessboard, they must be thrown away.
If it is required to keep K coins on the board, what is the minimum
moves you have to take?
Output -1 if you can not meet this requirement.
The first line of the input are two positive
integers n, representing the size of the board.
For the next n line(s), each line has m numbers of
characters, with 'o' indicating a coin, '.' indicates an empty grid.
The last line is a positive integer k,
indicating the number of coins to be retained.
30% small input: 1 <= n,m <= 5, 0 < k < 25
40% medium input: 1 <= n,m <= 10, 0 < k < 100
30% large input: 1 <= n,m <= 100, 0 < k < 10000
sample input:
3 4
.o..
oooo
..o.
3
sample output:
2
My temporary answer
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
public class main {
String[][] inputArray;
int n;
int m;
int k;
int totalCoin = 0;
int step = 0;
public static void main(String[] args) {
main temp = new main();
temp.readData();
}
public void readData() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
inputArray = new String [n][m];
sc.nextLine(); // skipping
for (int i = 0; i < n; i++) {
String temp = sc.nextLine();
for (int j = 0; j < m; j++) {
if ((temp.charAt(j) + "").equals("o")) totalCoin++;
inputArray[i][j] = temp.charAt(j) + "";
}
}
k = sc.nextInt();
int result = 0;
if (totalCoin >= k) {
result = findMaxAndMove();
System.out.println(result);
}
}
public String findNextMove() {
Map<String,Integer> tempList = new HashMap<String,Integer>();
tempList.put("up", up());
tempList.put("down", down());
tempList.put("left", left());
tempList.put("right", right());
Map.Entry<String, Integer> maxEntry = null;
for (Entry<String,Integer> temp : tempList.entrySet()) {
if (maxEntry == null || temp.getValue() > maxEntry.getValue()) {
maxEntry = temp;
}
}
Map<String,Integer> maxList = new HashMap<String,Integer>();
for (Entry<String,Integer> temp : tempList.entrySet()) {
if (temp.getValue() == maxEntry.getValue()) {
maxList.put(temp.getKey(), temp.getValue());
}
}
// return maxList.entrySet().iterator().next().getKey();
if (maxList.size() > 1) {
// how to handle this case when more than 1 operations has the same max value???????????
return ??????????????
}
else {
return maxList.entrySet().iterator().next().getKey();
}
//
}
public int findMaxAndMove() {
int up = up();
int down = down();
int left = left();
int right = right();
if ((totalCoin - up) == k) {
step++;
return step;
}
if ((totalCoin - down) == k) {
step++;
return step;
}
if ((totalCoin - left) == k) {
step++;
return step;
}
if ((totalCoin - right) == k) {
step++;
return step;
}
if (totalCoin - up < k && totalCoin - down < k && totalCoin - left < k && totalCoin - right < k) return -1;
else {
switch (findNextMove()) {
case "up" :
totalCoin -= up;
this.moveUp();
break;
case "down" :
totalCoin -= down;
this.moveDown();
break;
case "left" :
totalCoin -= left;
this.moveLeft();
break;
case "right" :
totalCoin -= right();
this.moveRight();
break;
}
step++;
return findMaxAndMove(); // going to next move
}
}
public String[] createBlankRow() {
String[] temp = new String[m];
for (int i = 0; i < m; i++) {
temp[i] = ".";
}
return temp;
}
public int up() {
int coinCounter = 0;
for (int i = 0; i < m; i++) {
if (inputArray[0][i].equals("o")) {
coinCounter++;
}
}
return coinCounter;
}
public void moveUp() {
// going up
for (int i = 0; i < n - 1; i++) {
inputArray[i] = inputArray[i + 1];
}
inputArray[n-1] = createBlankRow();
}
public int down() {
int coinCounter = 0;
for (int i = 0; i < m; i++) {
if (inputArray[n-1][i].equals("o")) {
coinCounter++;
}
}
return coinCounter;
}
public void moveDown() {
// going down
for (int i = n-1; i > 1; i--) {
inputArray[i] = inputArray[i - 1];
}
inputArray[0] = createBlankRow();
}
public int left() {
int coinCounter = 0;
for (int i = 0; i < n; i++) {
if (inputArray[i][0].equals("o")) {
coinCounter++;
}
}
return coinCounter;
}
public void moveLeft() {
// going left
for (int i = 0; i < n; i++) {
for (int j = 0; j < m-1; j++) {
inputArray[i][j] = inputArray[i][j+1];
}
inputArray[i][m-1] = ".";
}
}
public int right() {
int coinCounter = 0;
for (int i = 0; i < n; i++) {
if (inputArray[i][m-1].equals("o")) {
coinCounter++;
}
}
return coinCounter;
}
public void moveRight() {
// going right
for (int i = 0; i < n; i++) {
for (int j = m-1; j > 0; j--) {
inputArray[i][j] = inputArray[i][j-1];
}
inputArray[i][0] = ".";
}
}
public void printboard() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
System.out.print(inputArray[i][j]);
}
System.out.println();
}
}
}
I suspect you didn't find the right algorithm to solve the problem. To find a solution, not only the reachable boards with some special coin count are of concern but all. You must build up a tree of reachable boards. Each node in this tree is connected to its child nodes by an operation. That's were recursion enters the scene. You stop
when you reach your goal (mark this branch as possible solution) or
when it got impossible to reach the goal with further operations (too few coins left)
when the next operation would reach a board already visited in this branch.
In this tree all shortest branches marked as possible solution are the actual solutions. If no branch is marked as possible solution there is no solution and you have to output -1.
Here is my solution
public class CoinsMover {
public static List<String> getMinMoves(Character[][] board, int k, List<String> moves) {
if (!movesAreValid(moves, board)) {
return null;
}
int currentAmountOfCoins = getCoinsOnBoard(board);
// All good no need to move any thing
if (currentAmountOfCoins == k) {
moves.add("done");
return moves;
}
// Moved to much wrong way
if (currentAmountOfCoins < k) {
return null;
}
List<String> moveRight = getMinMoves(moveRight(board), k, getArrayWithApendded(moves, "right"));
List<String> moveLeft = getMinMoves(moveLeft(board), k, getArrayWithApendded(moves, "left"));
List<String> moveUp = getMinMoves(moveUp(board), k, getArrayWithApendded(moves, "up"));
List<String> moveDown = getMinMoves(moveDown(board), k, getArrayWithApendded(moves, "down"));
List<List<String>> results = new ArrayList<>();
if (moveRight != null) {
results.add(moveRight);
}
if (moveLeft != null) {
results.add(moveLeft);
}
if (moveUp != null) {
results.add(moveUp);
}
if (moveDown != null) {
results.add(moveDown);
}
if (results.isEmpty()) {
return null;
}
List<String> result = results.stream().sorted(Comparator.comparing(List::size)).findFirst().get();
return result;
}
private static boolean movesAreValid(List<String> moves, Character[][] board) {
long ups = moves.stream().filter(m -> m.equals("up")).count();
long downs = moves.stream().filter(m -> m.equals("down")).count();
long lefts = moves.stream().filter(m -> m.equals("left")).count();
long rights = moves.stream().filter(m -> m.equals("right")).count();
boolean verticalIsFine = ups <= board.length && downs <= board.length;
boolean horizontalIsFine = lefts <= board[0].length && rights <= board[0].length;
return verticalIsFine && horizontalIsFine;
}
private static List<String> getArrayWithApendded(List<String> moves, String move) {
List<String> result = new ArrayList<>(moves);
result.add(move);
return result;
}
private static Character[][] moveRight(Character[][] board) {
Character result[][] = new Character[board.length][board[0].length];
// Cleaning left column
for (int i = 0; i < board.length; i++)
result[i][0] = '.';
for (int row = 0; row < board.length; row++) {
for (int column = 0; column < board[row].length - 1; column++) {
result[row][column + 1] = board[row][column];
}
}
return result;
}
private static Character[][] moveLeft(Character[][] board) {
Character result[][] = new Character[board.length][board[0].length];
// Cleaning right column
for (int i = 0; i < board.length; i++)
result[i][board[i].length - 1] = '.';
for (int row = 0; row < board.length; row++) {
for (int column = 1; column < board[row].length; column++) {
result[row][column - 1] = board[row][column];
}
}
return result;
}
private static Character[][] moveDown(Character[][] board) {
Character result[][] = new Character[board.length][board[0].length];
// Cleaning upper row
for (int i = 0; i < board[board.length - 1].length; i++)
result[0][i] = '.';
for (int row = board.length - 1; row > 0; row--) {
result[row] = board[row - 1];
}
return result;
}
private static Character[][] moveUp(Character[][] board) {
Character result[][] = new Character[board.length][board[0].length];
// Cleaning upper row
for (int i = 0; i < board[board.length - 1].length; i++)
result[board.length - 1][i] = '.';
for (int row = 0; row < board.length - 1; row++) {
result[row] = board[row + 1];
}
return result;
}
private static int getCoinsOnBoard(Character[][] board) {
int result = 0;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
if (board[i][j] == 'o') {
result++;
}
}
}
return result;
}
public static void main(String... args) {
Character[][] mat = {{'.', 'o', '.', '.'}, {'o', 'o', 'o', 'o'}, {'.', '.', 'o', '.'}};
List<String> result = getMinMoves(mat, 3, new ArrayList<>());
if (result == null) {
System.out.println(-1);//output [right, right, done]
}
System.out.println(result);
}
}
I admit it was hard for me to search for duplicates so instead I am using a list of string which wrights the path you need to take to get to the solution. Now let's look at stopping condition first if current moves are invalid return null example of invalid moves is if you have a table with 4 columns in you moved right 5 times same goes for rows and moves up/down. Second, if board holds the neede amount we are done. And the last if board hold less we have failed. So now what algorithm is trying to do is to step in each direction in search of result and from here proceed recursivly.
You can find the solution below. A few points to note.
Whenever you see a problem that mentions moving an array in 1 direction, it's always a good idea to define an array of possible directions and loop through it in the recursive function. This would prevent you from confusing yourself.
The idea is to count coins by row and column so that you have a way to find out the remaining coins after each move in linear time.
The remaining job is to just loop through the possible directions in your recursive functions to find a possible solution.
As the recursive function may run in a circle and come back to one of the previous locations, you should/can improve the recursive function further by maintaining a Map cache of previous partial solutions using the curRowIdx and curColIdx as key.
public static void main(String[] args) {
char[][] board = {{'.', 'o', '.', '.'},
{'o', 'o', 'o', 'o'},
{'.', '.', 'o', '.'}};
CoinMoveSolver solver = new CoinMoveSolver(board);
System.out.println(solver.getMinimumMove(3));
}
static class CoinMoveSolver {
int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
char[][] board;
int[] rowCount;
int[] colCount;
int height;
int width;
int totalCoins;
public CoinMoveSolver(char[][] board) {
// Set up the board
this.board = board;
this.height = board.length;
this.width = board[0].length;
// Count how many coins we have per row,
// per column and the total no. of coins
this.rowCount = new int[height];
this.colCount = new int[width];
for (int i = 0 ; i < board.length ; i++) {
for (int j = 0 ; j < board[i].length ; j++) {
if (board[i][j] == 'o') {
this.rowCount[i]++;
this.colCount[j]++;
totalCoins++;
}
}
}
}
// Returns the number of coins if the top left
// corner of the board is at rowIdx and colIdx
private int countCoins(int rowIdx, int colIdx) {
int sumRow = 0;
for (int i = rowIdx ; i < rowIdx + height ; i++) {
if (i >= 0 && i < height)
sumRow += rowCount[i];
}
int sumCol = 0;
for (int j = colIdx ; j < colIdx + width ; j++) {
if (j >= 0 && j < width)
sumCol += colCount[j];
}
return Math.min(sumRow, sumCol);
}
public int getMinimumMove(int targetCoinCount) {
if (totalCoins < targetCoinCount)
return -1;
else if (totalCoins == targetCoinCount)
return 0;
else
return this.recursiveSolve(0, 0, -1, 0, targetCoinCount);
}
private boolean isOppositeDirection(int prevDirectionIdx, int curDirectionIdx) {
if (prevDirectionIdx < 0)
return false;
else {
int[] prevDirection = directions[prevDirectionIdx];
int[] curDirection = directions[curDirectionIdx];
return prevDirection[0] + curDirection[0] + prevDirection[1] + curDirection[1] == 0;
}
}
private int recursiveSolve(int curRowIdx, int curColIdx, int prevDirectionIdx, int moveCount, int targetCoinCount) {
int minMove = -1;
for (int i = 0 ; i < directions.length ; i++) {
if (!this.isOppositeDirection(prevDirectionIdx, i)) {
int[] direction = directions[i];
int nextRowIdx = curRowIdx + direction[0];
int nextColIdx = curColIdx + direction[1];
int coinCount = this.countCoins(nextRowIdx, nextColIdx);
// If this move reduces too many coins, abandon
if (coinCount < targetCoinCount)
continue;
// If this move can get us the exact number of
// coins we're looking for, break the loop
else if (coinCount == targetCoinCount) {
minMove = moveCount + 1;
break;
} else {
// Look for the potential answer by moving the board in 1 of the 4 directions
int potentialMin = this.recursiveSolve(nextRowIdx, nextColIdx, i, moveCount + 1, targetCoinCount);
if (potentialMin > 0 && (minMove < 0 || potentialMin < minMove))
minMove = potentialMin;
}
}
}
// If minMove is still < 0, that means
// there's no solution
if (minMove < 0)
return -1;
else
return minMove;
}
}

Write the integers of an array vertically

I know this is probably very simple but I really can't seem to understand how to write the integers vertically. For instance, there is an array that has 4 integers which are 9, 21, 63, and 501, the outcome would be the following
9 2 5 6
1 0 3
1
This is a small step of my program and probably the easiest but I can't understand how to do it :(
Can someone please help me or guide me so I can finish my program
Try this pseudo code
int[] list = new int[] {9,21,63,501};
bool finished = false;
if (list.Count > 0) {
for (var j=0;!finshed; j++) {
finished = true;
for (var i = 0; i<list.Count;i++) {
String val = list[i].ToString();
if (val.length>j) {
write(val.charAt(j));
finished = false;
}
}
}
}
I have created a very modular and easy to follow solution.
Edit: Converted digitAtIndex() to a purely numerical calculation.
Kept the original and called it digitAtStrIndex().
public class IntegerColumns {
public IntegerColumns() {
int[] arr = new int[] {9, 21, 501, 63};
printColumnMajorOrder(arr);
}
public static void main(String[] args) {
new IntegerColumns();
}
// --------------------- Primary Functions --------------------------
// Prints out an Array of Integers, each in a vertical column
public void printColumnMajorOrder(int[] arr) {
int cols = arr.length;
int rows = maxDigits(arr);
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
int d = digitAtIndex(arr[c], r);
System.out.printf("%s\t", d >= 0 ? Integer.toString(d) : " ");
}
System.out.println();
}
}
// Returns the length of an Integer
public int numDigits(int i) {
if (i <= 0) return 0;
return (int)Math.floor(Math.log10(i))+1;
}
// Numeric calculation to find a digit at a specified index
public int digitAtIndex(int num, int index) {
int digits = numDigits(num);
int deg = digits - index - 1;
int pow = (int)Math.pow(10, deg);
return pow > 0 ? (int)(num/pow)%10 : -1;
}
// Returns the number of digits for the longest Integer in an Array
public int maxDigits(int[] arr) {
int max = 0;
for (int i : arr) {
int size = numDigits(i);
if (size > max) max = size;
}
return max;
}
// ---------------------- Extra Functions ---------------------------
// Hybrid of Integer and Substrings - String manipulation = slow
public int digitAtStrIndex(int number, int i) {
String n = Integer.toString(number);
return n.length() > i ? Integer.parseInt(n.substring(i, i+1)) : -1;
}
// Prints the digits of a number vertically
public void printNumberVertical(int num) {
for (int i = 0; i < numDigits(num); i++)
System.out.println(digitAtIndex(num, i));
}
}
`public class VerticalPrintService {
private int[] data;
public VerticalPrintService( int[] intArray ) {
this.data = intArray;
}
public void printVertically(){
int cols = data.length; // # of columns
int rows = getRows(); // # of rows
System.out.println("cols: " + cols);
System.out.println("rows: " + rows);
String[][] matrix = new String[rows][cols];
int rowIndex = 0;
int colIndex = 0;
// populate 2d array
for ( int i : data ) {
String str = String.valueOf(i);
for ( int j = 0; j < str.length(); j++ ) {
matrix[rowIndex][colIndex] = String.valueOf(str.charAt(j));
rowIndex++;
}
colIndex++;
rowIndex = 0;
}
// print
for ( int i = 0; i < rows; i++ ) {
for ( int j = 0; j < cols; j++ ) {
if ( null == matrix[i][j] ) {
System.out.print("\t");
} else {
System.out.print( matrix[i][j] + "\t" );
}
}
System.out.println();
}
}
private int getRows(){
int max = 0;
for ( int i : data ) {
int len = String.valueOf(i).length();
if ( len > max ) {
max = len;
}
}
return max;
}
}`
and in your main method
`public static void main(String[] args) {
int[] array = { 9, 53, 501, 90 };
VerticalPrintService vps = new VerticalPrintService(array);
vps.printVertically();
}`

Categories