Java - How to find an element in a 2D Array using recursion - java

Here is the problem: Given a 2D int Array called data, return true if any value in the Array equals given element. Otherwise return false. Your program should work with arbitrarily sized Arrays in either dimension, including ragged (or irregular) arrays. For example:
int[][] table = new int[][] { {5, 2, 8, 5, 61}, {3, 9, 6}, {10, 42, 53, 45}};
searchTable(table, 45) returns true
searchTable(table, 100) returns false
Caveats:
Cannot use any kind of loops, method cannot be static, cannot use class instance variables.
Here is my code so far:
public boolean searchTable(int[][] data, int element){
boolean result = false;
int a = searchRow(data[data.length-1], data.length -1);
int b = searchCol(data[a], data.length -1);
if (data[a][b] == element)
result = true;
else
result = false;
return result;
}
public int searchRow(int [] row, int index)
{
if (row.length != 0)
return index;
else
{
return searchRow(row, index + 1);
}
}
public int searchCol(int [] col, int index)
{
if (col.length != 0 )
return index;
else
{
return searchCol(col, index + 1);
}
}
My output is false for everything.

Here is one approach that solves the problem recursively,
public boolean searchTable(int[][] data, int element) {
return searchTable(data, element, 0);
}
private boolean searchTable(int[][] data, int element, int p) {
if (p < 0 || p > data.length) {
return false;
}
int[] row = getRow(data, p);
if (searchRow(row, element, 0)) {
return true;
}
return searchTable(data, element, 1 + p);
}
private boolean searchRow(int[] data, int element, int p) {
if (data == null || p >= data.length) {
return false;
}
if (data[p] == element) {
return true;
}
return searchRow(data, element, 1 + p);
}
public int[] getRow(int[][] in, int x) {
if (in == null || x >= in.length) {
return null;
}
return in[x];
}
public static void main(String[] args) {
// I named the class Question.
Question question = new Question();
int[][] table = new int[][] { { 5, 2, 8, 5, 61 }, { 3, 9, 6 },
{ 10, 42, 53, 45 } };
System.out.println(question.searchTable(table, 45));
System.out.println(question.searchTable(table, 100));
}
Output is
true
false

One approach that will return the result :
public class RecursiveSearch{
int rowCount = 0;
int columnCount = 0;
boolean result = false;
public boolean searchTable(int[][] data, int element){
if(data[rowCount].length==columnCount)
{
rowCount++;
columnCount=0;
}
if(data.length > rowCount)
{
if(data[rowCount][columnCount] == element)
{
result = true;
}
else
{
columnCount++;
searchTable(data, element);
}
}
return result;
}
public static void main(String[] args) {
int[][] table = new int[][] { {5, 2, 8, 5, 61}, {3, 9, 6}, {10, 42, 53, 45}};
System.out.println(new RecursiveSearch().searchTable(table, 45));
}
}

Related

How to find all the solutions for a NQueens problem given that one queen is fixed at some column?

This is all about the famous NQueens problem. My program works fine (backtrack approach). It finds all the solutions for a given board size.
Code is shown below.
I'm trying to modify the code so that I can find all the solutions for a given column of the first queen. I don't want to change the position of first queen. For an example it will provide me with the solution of
[2, 0, 3, 1, 4] and [2, 4, 1, 3, 0]
when I set the first queen at 2, board size 5 (third column, index starts from zero).
I tried this by setting different values for k (and board[k] as well) but doesn't quite reach the goal.
Any hints will be appreciated.
Here is my code. Removed details about place method since it shouldn't be changed to achieve my new goal.
public class NQueensAllSolutions
{
// Board size
static int size = 8;
// One dimensional array to store the column number for all queens.
static int[] board = new int[size];
// This method will check the validity for a new queen. works fine.
static boolean place(int k)
{
.
.
}
public static void main(String[] args)
{
int k;
long t=0; // for counting total found solutions
k = 0;
board[k] = -1;
while(k >= 0) {
board[k]++;
while(board[k] < size && !(place(k))) board[k]++;
if(board[k] < size) {
if(k == size-1) { // a solution is found.
t++;
//System.out.println("\n\nTotal: "+t+" --> "+Arrays.toString(board));
}
else {
k++; board[k] = -1;
}
}
else {
k--; // backtrack.
}
}
System.out.println("\n\nTotal: "+t);
}
}
Just keep k greater than 0 in the while loop:
import java.util.Arrays;
public class Queens
{
static int size = 5;
static int[] board = new int[size];
static boolean isValid(int k)
{
int c1 = board[k];
int c2 = board[k];
for(int r=k-1;r>=0;r--)
{
c1--;
c2++;
if(board[r] == board[k] || board[r] == c1 || board[r] == c2)
return false;
}
return true;
}
public static void main(String[] args)
{
int t = 0;
// Set the first queen position
board[0] = 2;
int k = 1;
board[k] = -1;
// k must stay greater than 0
while(k >= 1) {
board[k]++;
while(board[k] < size && !isValid(k))
board[k]++;
if(board[k] < size) {
if(k == size-1) {
t++;
System.out.println("Solution "+t+" --> "+Arrays.toString(board));
}
else {
k++;
board[k] = -1;
}
}
else {
k--;
}
}
}
}
Output:
Solution 1 --> [2, 0, 3, 1, 4]
Solution 2 --> [2, 4, 1, 3, 0]
UPDATE
Here is a generalized version that can force a queen at position (fixedRow, fixedCol).
The key change is the new getNextCol() method, which is used to get the next possible column for a queen. On row fixedRow, the only possible column is fixedCol. On the other rows, all columns are possible.
import java.util.Arrays;
public class Queens
{
static int size = 5;
static int fixedRow = 2;
static int fixedCol = 0;
static int[] board = new int[size];
static boolean isValid(int k)
{
int c1 = board[k];
int c2 = board[k];
for(int r=k-1;r>=0;r--)
{
c1--;
c2++;
if(board[r] == board[k] || board[r] == c1 || board[r] == c2)
return false;
}
return true;
}
static int getNextCol(int k, int col)
{
if(k == fixedRow) {
// Only one possible move on this row
return col == -1 ? fixedCol : size;
}
else {
// Try the next column
return col+1;
}
}
public static void main(String[] args)
{
int t = 0;
int k = 0;
board[k] = -1;
while(k >= 0) {
board[k] = getNextCol(k, board[k]);
while(board[k] < size && !isValid(k))
board[k] = getNextCol(k, board[k]);
if(board[k] < size) {
if(k == size-1) {
t++;
System.out.println("Solution "+t+" --> "+Arrays.toString(board));
}
else {
k++;
board[k] = -1;
}
}
else {
k--;
}
}
}
}
Output:
Solution 1 --> [1, 3, 0, 2, 4]
Solution 2 --> [4, 2, 0, 3, 1]

How can I use memoization to improve the run time of this algorithm?

The problem is stated:
If we can assign either a positive or negative sign to each integer in
a set of integers, how many ways can we sum the signed integers to
equal a target value? We must use every integer in the set.
Eg [1, 2, 3, 2], target = 0
Two ways [-1, 2, -3, 2], and [1, -2, 3,
-2]
My solution is as follows (java)
public static void main(String[] args) {
int[] nums = {1, 2, 3, 2};
int x = helper(0, 0, nums, 0);
System.out.println(x);
}
private static int helper(int step, int sumSoFar, int[] nums, int target) {
if (step == nums.length) {
return sumSoFar == target ? 1 : 0;
}
return
helper(step + 1, sumSoFar + nums[step], nums, target)
+
helper(step + 1, sumSoFar - nums[step], nums, target);
}
I understand that there are many possible repeated calculations in a brute force solution, but I can't understand if passing in the sumSoFar variable is effectively forming a memoization technique?
If not, how can I use memoization to improve the runtime performance of this algorithm?
You can use hash map for solving this problem with memorization (Ex: Guava Table)
Table<Integer, Integer, Integer> calculated = HashBasedTable.create();
private static int helper(int step, int sumSoFar, int[] nums, int target) {
if (step == nums.length) {
return sumSoFar == target ? 1 : 0;
}
if (calculated.contains(step, sumSoFar)) {
return calculated.get(step, sumSoFar)
}
int result = helper(step + 1, sumSoFar + nums[step], nums, target)
+
helper(step + 1, sumSoFar - nums[step], nums, target);
calculated.put(step, sumSoFar, result);
return result;
}
You probably want to achieve "memoization" with following algorithm. I have added one more parameter in recursion - rest which can be absolute positive or absolute negative sum of the non-seen elements. So it breaks recursion if there is no chance to reach the target.
With this approach, worst case is still O(2^n) - i.e. [0,0,0,0], but in practice it is faster.
Note: assumption is that elements in nums are positive, if not you can make them in O(n).
public static void main(String[] args) {
int[] nums = {1, 2, 3, 2};
int totalSumSum = arraySum(nums);
int x = helper(-1, 0, nums, 0, totalSumSum);
System.out.println(x);
}
private static int helper(int step, int sumSoFar, int[] nums, int target, int rest) {
if (step == nums.length-1) {
return sumSoFar == target ? 1 : 0;
}
int nextStep = step+1;
int nextSumPos = sumSoFar + nums[nextStep];
int nextSumNeg = sumSoFar - nums[nextStep];
int nextRest = rest - nums[nextStep];
boolean pos = false;
if ((nextSumPos > target && nextSumPos - nextRest > target) ||
(nextSumPos < target && nextSumPos + nextRest < target)) { /* do nothing */ }
else { pos = true; }
boolean neg = false;
if ((nextSumNeg > target && nextSumNeg - nextRest > target) ||
(nextSumNeg < target && nextSumNeg + nextRest < target)) { /* do nothing */ }
else { neg = true; }
if (pos && neg) {
return helper(nextStep, nextSumPos, nums, target, nextRest)
+ helper(nextStep, nextSumNeg, nums, target, nextRest);
}else if (pos && !neg) {
return helper(nextStep, nextSumPos, nums, target, nextRest);
} else if (!pos && neg) {
return helper(nextStep, nextSumNeg, nums, target, nextRest);
} else { /* !pos && !neg */
return 0;
}
}
private static int arraySum(int[] nums) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
return sum;
}

Function to see if there is a break in circuit (2D Array)

I want to create a function that lets me see if there is a break in a circuit which I've stored in a 2D Array by returning either true or false. For simplicity sake i have modeled the circuit using 1's and 0's. With 1's being components and 0's being spaces. I have tried messing with recursive functions however to no avail and am pretty much stuck at this point.
For example:
1 1 1
1 0 1
1 1 1
I would like this to return true as all the 1's are connected in series. This 2D array would be visualized as seen here.
1 1 1
0 0 1
1 1 1
I would like this to return false as there is a break in the circuit as
as shown here.
Any solutions or guidance would be much appreciated!
My current code is shown below. It returns incomplete when I used the completeCircuit as an input however returns complete when I have the incompleteCircuit as an input.
public class TraversalTest
{
boolean complete = false;
int runs = 0;
public static void main(String[] args)
{
TraversalTest traversal = new TraversalTest();
}
public TraversalTest()
{
Cell[][] completeCircuit =
{
{ new Cell( 0, 0, 1), new Cell( 1, 0, 1), new Cell( 2, 0, 1) },
{ new Cell( 0, 1, 1), new Cell( 1, 1, 0), new Cell( 2, 1, 1) },
{ new Cell( 0, 2, 1), new Cell( 1, 2, 1), new Cell( 2, 2, 1) }
};
Cell[][] incompleteCircuit =
{
{ new Cell( 0, 0, 1), new Cell( 1, 0, 1), new Cell( 2, 0, 1) },
{ new Cell( 0, 1, 0), new Cell( 1, 1, 0), new Cell( 2, 1, 1) },
{ new Cell( 0, 2, 1), new Cell( 1, 2, 1), new Cell( 2, 2, 1) }
};
completeCircuit[1][0].connected = true;
int cellsLeft = (numOfPositiveCells(completeCircuit));
checkComplete(completeCircuit, completeCircuit[1][0], cellsLeft);
incompleteCircuit[1][0].connected = true;
int cellsLeft1 = (numOfPositiveCells(incompleteCircuit));
checkComplete(incompleteCircuit, incompleteCircuit[1][0], cellsLeft1);
}
void checkComplete(Cell[][] circuit, Cell currentCell, int cellsLeft)
{
currentCell.connected = true;
if(cellsLeft > 0)
{
if(currentCell.x != 0 && circuit[currentCell.x-1][currentCell.y].value == 1 &&
circuit[currentCell.x-1][currentCell.y].connected == false)
{
cellsLeft--;
checkComplete(circuit, circuit[currentCell.x-1][currentCell.y], cellsLeft);
}
else if(currentCell.x != 2 &&circuit[currentCell.x+1][currentCell.y].value == 1 &&
circuit[currentCell.x+1][currentCell.y].connected == false)
{
cellsLeft--;
checkComplete(circuit, circuit[currentCell.x+1][currentCell.y], cellsLeft);
}
else if(currentCell.y != 0 && circuit[currentCell.x][currentCell.y-1].value == 1 &&
circuit[currentCell.x][currentCell.y-1].connected == false)
{
cellsLeft--;
checkComplete(circuit, circuit[currentCell.x][currentCell.y-1], cellsLeft);
}
else if(currentCell.y != 2 && circuit[currentCell.x][currentCell.y+1].value == 1 &&
circuit[currentCell.x][currentCell.y+1].connected == false)
{
cellsLeft--;
checkComplete(circuit, circuit[currentCell.x][currentCell.y+1], cellsLeft);
}
else
{
complete = false;
System.out.println("Incomplete");
}
}
else
{
complete = true;
System.out.println("Complete");
}
}
int numOfPositiveCells(Cell[][] circuit)
{
int num = 0;
for(int x=0; x < 3; x++)
for(int y=0; y < 3; y++)
if(circuit[x][y].value == 1)
num++;
return num;
}
}
class Cell
{
public boolean connected;
public int value;
public int x;
public int y;
public Cell(int x, int y, int value)
{
this.x = x;
this.y = y;
this.value = value;
}
}
I think checking that every cell has 2 connections should work for your use cases as we only look for series connections.
You just need to go through your array and make sure that all live cells have 2 and only 2 live cells connected to it
I'd suggest you make a dedicated class, this way you don't have to keep passing the circuit around in all the methods:
class CircuitChecker {
private final Cell[][] circuit;
private final int nbRows, nbCols;
public CircuitChecker(Cell[][] circuit) {
this.circuit = circuit;
this.nbRows = circuit.length;
this.nbCols = circuit[0].length;
}
public boolean isCircuitComplete() {
boolean isComplete = true;
for(int col = 0; col<nbCols; col++) {
for (int row = 0; row < nbRows; row++) {
if(cellIsLive(col, row) && !cellHas2LiveConnections(col, row)) {
isComplete = false;
break;
}
}
}
return isComplete;
}
private boolean cellIsLive(int col, int row) {
return circuit[row][col].value == 1;
}
private boolean cellHas2LiveConnections(int col, int row) {
Cell left = col > 0 ? circuit[col-1][row] : null;
Cell right = col < nbCols-1 ? circuit[col+1][row] : null;
Cell up = row > 0 ? circuit[col][row-1] : null;
Cell down = row < nbRows-1 ? circuit[col][row+1] : null;
int nbConnections = Stream.of(left, right, up, down)
.filter(Objects::nonNull)
.mapToInt(c -> c.value)
.sum();
return nbConnections == 2;
}
}
you call it this way:
new CircuitChecker(completeCircuit).isCircuitComplete();
new CircuitChecker(incompleteCircuit).isCircuitComplete();
One more thing, the fields in your class Cell should be private (and even maybe final) and you should access them via getters.

Finding snake sequence in XY graph - Java

I am working on a problem to try to find what is called a Snake Sequence in a typical XY graph (aka grid). A Snake sequence is defined as a sequence of numbers where each new number, which can only be located to the right or down of the current number, is either plus or minus one. For example, if you are in the center of the graph, you can either move right (if that number is + or - 1) or move down (if that number is + or - 1). The goal of the problem is to find the longest path (aka Snake Sequence) through the graph (keeping in mind you can only chart a path to a new cell whose value is +- 1 with the current cell).
So, for the following XY graph, the longest snake sequence is: 9, 8, 7, 6, 5, 6, 7
9, 6, 5, 2
8, 7, 6, 5
7, 3, 1, 6
1, 1, 1, 7
Below is my code, which does not seem to work.
Question: How would you solve this problem above? (I offer my code showing what I have thus far, but it does not work)
import java.util.ArrayList;
public class SnakeSequence {
private final int maxX = 3;
private final int maxY = 3;
private final int[][] board = new int[][]{
{1, 2, 3, 4},
{2, 1, -1, 5},
{3, 0, -1, 6},
{6, 2, 1, 7}
};
private ArrayList<Integer> findSequence(int xPos,
int yPos, ArrayList<Integer> currentPath) {
currentPath.add(board[yPos][xPos]);
ArrayList<Integer> pathRight = new ArrayList<Integer>(currentPath);
ArrayList<Integer> pathDown = new ArrayList<Integer>(currentPath);
if (xPos < maxX || yPos < maxY) {
if (yPos < maxY && (board[yPos + 1][xPos] + 1 == board[yPos][xPos] ||
board[yPos + 1][xPos] - 1 == board[yPos][xPos])) {
pathDown = findSequence(xPos, yPos + 1, currentPath);
}
if (xPos < maxX && (board[yPos][xPos + 1] + 1 == board[yPos][xPos] ||
board[yPos][xPos + 1] - 1 == board[yPos][xPos])) {
pathRight = findSequence(xPos + 1, yPos, currentPath);
}
if (pathDown.size() > pathRight.size()) {
return pathDown;
} else {
return pathRight;
}
}
return currentPath;
}
private void getSequence() {
ArrayList<Integer> currentPath = new ArrayList<Integer>();
ArrayList<Integer> result;
result = findSequence(0, 0, currentPath);
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i));
}
}
public static void main(String[] args) {
SnakeSequence sequence = new SnakeSequence();
sequence.getSequence();
}
}
You can imagine your table as an oriented graph, then you problem is just to find the longest path.
Fortunatly for you, only moving down and right is allowed, so your graph is acyclic, so you can use algorithms like critical path method.
This is how your graph would look like:
However, you want to find longest path between any two cells. To do that, I would compute for each cell the longest path starting at that cell. It is simmilar to what you do, but you compute same thing more times. Consider this:
6 -> 5
| |
v v
7 -> 6
At both 5 and 7 you compute how long is the path from 6 at down right, and that is useless repeated computation. In worst case scenario, this could lead to exponential time consumption, while the problem can be resolved in linear time!
Moreover, there is no guarantee that the longest path will start at (0,0).
(one possible) Solution:
Compute longest path from each cell, starting from bottom-right to upper-left. At each cel.. remember how long the longest path from that cell is, and witch way from that cell the path leads. (I will measure path length by number of cells on it). So for example, for the only 8 in your grapth, we would remeber [length=8, direction=right].
Why so complicated? Because it is now extramly easy to compute longest path at a cell, if we know the longest path of the cells to the right and down. Example (I made up):
The correct data for 2 now would be [length=4, direction=down] because can't go from 2 to 4.
You can also keep globally longest path and it's start. After the computation is complete, just walk the longest path from that start through the direction and write the numbers, position or whatever you need.
Apologies for my Java (I am primarily a c# programmer) but here is one solution. I separated out the algorithm that discovers the snakes from the algorithm (implementing the interface ISnakeProcessor) that processes each one. That way you could enhance the code to, e.g., collect the snake with the largest sum of values, or collect all the longest snakes, in case there are more than one, by adding more ISnakeProcessor classes.
import java.util.*;
import java.lang.*;
class Rextester
{
public static void main(String args[])
{
SnakeSequence sequence = new SnakeSequence();
sequence.getSequence();
}
}
interface ISnakeProcessor
{
void process(List<Pair<Integer, Integer>> snake);
}
class SnakeSequence {
private final int[][] board;
public SnakeSequence()
{
this(new int[][]{
{1, 2, 3, 4},
{2, 1, -1, 5},
{3, 0, -1, 6},
{6, 2, 1, 7}
});
}
public SnakeSequence(int[][] board)
{
this.board = board;
}
public boolean isValid(int iRow, int iCol)
{
if (iRow < 0 || iRow >= board.length)
return false;
if (iCol < 0 || iCol >= board[iRow].length)
return false;
return true;
}
private boolean continuesInRow(int iRow, int iCol)
{
if (!isValid(iRow, iCol) || !isValid(iRow+1, iCol))
return false;
int myVal = board[iRow][iCol];
if (board[iRow+1][iCol] == myVal - 1 || board[iRow+1][iCol] == myVal + 1)
return true;
return false;
}
private boolean continuesInCol(int iRow, int iCol)
{
if (!isValid(iRow, iCol) || !isValid(iRow, iCol+1))
return false;
int myVal = board[iRow][iCol];
if (board[iRow][iCol+1] == myVal - 1 || board[iRow][iCol+1] == myVal + 1)
return true;
return false;
}
private boolean isHead(int iRow, int iCol)
{
if (!isValid(iRow, iCol))
return false;
if (isValid(iRow-1, iCol) && continuesInRow(iRow-1, iCol))
return false;
if (isValid(iRow, iCol-1) && continuesInRow(iRow, iCol-1))
return false;
return true;
}
private boolean isTail(int iRow, int iCol)
{
if (!isValid(iRow, iCol))
return false;
if (continuesInRow(iRow, iCol))
return false;
if (continuesInCol(iRow, iCol))
return false;
return true;
}
private void testHead()
{
System.out.println("Dumping list of heads");
for (int iRow = 0; iRow < board.length; iRow++)
{
for (int iCol = 0; iCol < board[iRow].length; iCol++)
{
boolean head = isHead(iRow, iCol);
boolean tail = isTail(iRow, iCol);
if (head && tail)
System.out.print(" B");
else if (head)
System.out.print(" H");
else if (tail)
System.out.print(" T");
else
System.out.print(" -");
}
System.out.println("");
}
}
private void walkSnake(ISnakeProcessor processor, int iRow, int iCol, ArrayList<Pair<Integer, Integer>> snake)
{
snake.add(new Pair<Integer, Integer>(iRow, iCol));
boolean isTail = true;
if (continuesInRow(iRow, iCol))
{
walkSnake(processor, iRow+1, iCol, snake);
isTail = false;
}
if (continuesInCol(iRow, iCol))
{
walkSnake(processor, iRow, iCol+1, snake);
isTail = false;
}
if (isTail)
{
processor.process(snake);
}
snake.remove(snake.size() - 1);
}
private void walkSnakes(ISnakeProcessor processor)
{
ArrayList<Pair<Integer, Integer>> snake = new ArrayList<Pair<Integer, Integer>>();
for (int iRow = 0; iRow < board.length; iRow++)
for (int iCol = 0; iCol < board[iRow].length; iCol++)
if (isHead(iRow, iCol))
walkSnake(processor, iRow, iCol, snake);
}
class LongestSnakeFinder implements ISnakeProcessor
{
private final SnakeSequence parent;
ArrayList<Pair<Integer, Integer>> longest = new ArrayList<Pair<Integer, Integer>>();
public LongestSnakeFinder(SnakeSequence parent)
{
this.parent = parent;
}
public void process(List<Pair<Integer, Integer>> snake)
{
if (snake.size() > longest.size())
{
longest.clear();
longest.addAll(snake);
}
}
public void dumpLongest()
{
System.out.format("The first encountered longest snake has length %d:\n", longest.size());
for (int i = 0; i < longest.size(); i++)
{
int iRow = longest.get(i).getFirst();
int iCol = longest.get(i).getSecond();
System.out.format(" (%d,%d): %d\n", iRow, iCol, parent.getValue(iRow, iCol));
}
}
}
public int getNRows() { return board.length; }
public int getNCols(int iRow) { return board[iRow].length; }
public int getValue(int iRow, int iCol) { return board[iRow][iCol]; }
public void getSequence() {
testHead();
LongestSnakeFinder finder = new LongestSnakeFinder(this);
walkSnakes(finder);
finder.dumpLongest();
}
}
class Pair<F, S> {
private F first; //first member of pair
private S second; //second member of pair
public Pair(F first, S second) {
this.first = first;
this.second = second;
}
public F getFirst() {
return first;
}
public S getSecond() {
return second;
}
}
Example run here: http://rextester.com/AKUFNL43897
Update - cleaned code a little. New sample run here: http://rextester.com/AVOAIY11573
And, the output:
Dumping list of heads
H - - -
- - B -
T - T -
B H T T
The first encountered longest snake has length 7:
(0,0): 1
(0,1): 2
(0,2): 3
(0,3): 4
(1,3): 5
(2,3): 6
(3,3): 7
Is this what you want?
Here is one simple way to correct your solution and avoid copying of path on every step
import java.util.ArrayList;
import java.util.Collections;
public class SnakeSequence {
private final int maxX = 3;
private final int maxY = 3;
private final int[][] board = new int[][]{
{1, 2, 3, 4},
{2, 1, -1, 5},
{3, 0, -1, 6},
{6, 2, 1, 7}
};
private ArrayList<Integer> findSequence(int xPos,
int yPos) {
ArrayList<Integer> pathRight = new ArrayList<Integer>();
ArrayList<Integer> pathDown = new ArrayList<Integer>();
if (yPos < maxY && (board[yPos + 1][xPos] + 1 == board[yPos][xPos] ||
board[yPos + 1][xPos] - 1 == board[yPos][xPos])) {
pathDown = findSequence(xPos, yPos + 1);
}
if (xPos < maxX && (board[yPos][xPos + 1] + 1 == board[yPos][xPos] ||
board[yPos][xPos + 1] - 1 == board[yPos][xPos])) {
pathRight = findSequence(xPos + 1, yPos);
}
ArrayList<Integer> ans;
if (pathDown.size() > pathRight.size()) {
ans = pathDown;
} else {
ans = pathRight;
}
ans.add(board[yPos][xPos]);
return ans;
}
private void getSequence() {
ArrayList<Integer> result;
result = findSequence(0, 0);
Collections.reverse(result);
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i));
}
}
public static void main(String[] args) {
SnakeSequence sequence = new SnakeSequence();
sequence.getSequence();
}
}
But this way it can work much faster for big arrays due to no recalculating the longest path every time you visiting the same number during recursion. Actually, in this version each number is visited at most twice. It's achieved through saving best solution for every node. Separate storage of path and it length allows not to copy path when it's not needed.
import java.util.ArrayList;
import java.util.Collections;
public class SnakeSequence {
private final int maxX = 3;
private final int maxY = 3;
private final int[][] board = new int[][]{
{1, 2, 3, 4},
{2, 3, -1, 5},
{3, 2, -1, 6},
{6, 1, 2, 3}
};
int[][] pathLength;
ArrayList<ArrayList<ArrayList<Integer>>> paths;
private ArrayList<Integer> findSequence(int xPos,
int yPos) {
if(pathLength[yPos][xPos] >= 0)
{
ArrayList<Integer> ans = new ArrayList<Integer>();
int length = pathLength[yPos][xPos];
ArrayList<Integer> path = paths.get(yPos).get(xPos);
for(int i = 0; i < length; i++)
ans.add(path.get(i));
return ans;
}
ArrayList<Integer> pathRight = new ArrayList<Integer>();
ArrayList<Integer> pathDown = new ArrayList<Integer>();
if (yPos < maxY && (board[yPos + 1][xPos] + 1 == board[yPos][xPos] ||
board[yPos + 1][xPos] - 1 == board[yPos][xPos])) {
pathDown = findSequence(xPos, yPos + 1);
}
if (xPos < maxX && (board[yPos][xPos + 1] + 1 == board[yPos][xPos] ||
board[yPos][xPos + 1] - 1 == board[yPos][xPos])) {
pathRight = findSequence(xPos + 1, yPos);
}
ArrayList<Integer> ans;
if (pathDown.size() > pathRight.size()) {
ans = pathDown;
} else {
ans = pathRight;
}
ans.add(board[yPos][xPos]);
paths.get(yPos).set(xPos,ans);
pathLength[yPos][xPos] = ans.size();
return ans;
}
private void getSequence() {
ArrayList<Integer> result;
pathLength = new int[maxX + 1][maxY + 1];
paths = new ArrayList<ArrayList<ArrayList<Integer>>>();
for(int y = 0; y <= maxY; y++)
{
ArrayList<ArrayList<Integer>> line = new ArrayList<ArrayList<Integer>>();
for(int x = 0; x <= maxX; x++)
{
line.add(null);
pathLength[y][x] = -1;
}
paths.add(line);
}
result = findSequence(0, 0);
Collections.reverse(result);
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i));
}
}
public static void main(String[] args) {
SnakeSequence sequence = new SnakeSequence();
sequence.getSequence();
}
}
Simple Recursive solution :
import java.util.ArrayList;
import java.util.List;
public class MaximumLengthSnakeSequence {
static int max = -1;
static List<Integer> maxListTemp = new ArrayList<>();
public static void main(String args[]) {
int count = 0;
int n = 4;
int m = 4;
int mat[][] = { { 9, 6, 5, 2 }, { 8, 7, 6, 5 }, { 7, 3, 1, 6 }, { 1, 1, 1, 7 }, };
List<Integer> maxList = new ArrayList<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
List<Integer> list = new ArrayList<>();
list.add(mat[i][j]);
List<Integer> testList = recur(i, j, count, mat, n, m, list);
if (maxList.size() < testList.size()) {
maxList = new ArrayList<>(testList);
}
maxListTemp.clear();
}
}
System.out.println("max is " + maxList);
}
static List<Integer> recur(int i, int j, int count, int mat[][], int n, int m, List<Integer> list) {
int curData = mat[i][j];
int rightData = 0;
int downData = 0;
if (j + 1 < n && i < m) {
rightData = mat[i][j + 1];
if (Math.abs(curData - rightData) == 1) {
list.add(rightData);
recur(i, j + 1, count + 1, mat, n, m, list);
list.remove(list.size() - 1);
}
}
if (count > max) {
max = count;
}
if (maxListTemp.size() < list.size()) {
maxListTemp = new ArrayList<>(list);
}
if (i + 1 < m && j < n) {
downData = mat[i + 1][j];
if (Math.abs(curData - downData) == 1) {
list.add(downData);
recur(i + 1, j, count + 1, mat, n, m, list);
list.remove(list.size() - 1);
}
}
return maxListTemp;
}
}

Java Recursion return boolean

Given an array of integers f, I want to see if f[k]=k for some k in the array. I'm having some trouble because I would like to return on the left and right half of the array, but I am not sure how to go about doing that. This is what I have so far:
public class Find {
int a = 0;
public boolean find(int[] f) {
if(f.length < 1) {
return false;
}
System.out.println(f[0] + " " + a);
if(f.length == 1 && f[0] == a) {
return true;
}
if(f.length == 1 && f[0] != a) {
return false;
}
int[] L = Arrays.copyOfRange(f, 0, f.length / 2);
int[] R = Arrays.copyOfRange(f, f.length / 2, f.length);
find(L);
a++;
//find(R);
return find(R); //only finds in the right half...
}
public static void main(String[] args) {
Find F = new Find();
int[] test = {0, 13, 2, 3, 4};
System.out.println(F.find(test));
}
}
You could do the following, you currently search the left side but do not return the result:
return find(R) || find(L);

Categories