I am working on a program that prints out a table filled with randomly-generated integers. Most of the logic is relatively straightforward and works pretty well. One thing I would like to do is to add up and print out total values for each column, as well as the final total of all the values in the table. I have searched around trying to find an answer but have had no luck with figuring it out.
rowNbr = 7; // ROW CONTROLS
colNbr = 5; //COLUMN CONTROLS
rpt01 = String.format("%0" + (colNbr-1) + "d", 0).replace("0",dash); //Redefine rpt01
colBld = String.format("|---------------|%s\n",rpt01); //Redefine colBld
String cnrTxt = "First Quarter";
System.out.printf(colBld);
System.out.printf("|%-15s",cnrTxt);
for(int i = 1; i < colNbr; i = i++){ //Open for loop (columns)
String regTxt = "Region " + i++;
System.out.printf("|%-10s",regTxt);
} //End for
System.out.printf("|\n");
//Initialize array
int sales[] = new int[100];
int idx = 0;
for(int i = 1; i <= rowNbr-3; i++){
String prodTxt = "Product " + i;
System.out.printf(colBld);
System.out.printf("|%-15s|",prodTxt);
for(int j = 0; j < colNbr-1; j++){ //Open for loop (columns 2)
sales[idx] = (int)(Math.random() * 16 + 1);
System.out.printf("%-10d|",sales[idx]);
idx++;
} //End for
System.out.printf("\n");
} //End for
int totalNbr = 0; //Placeholder zero
int regNbr = 0; //Placeholder zero
String totalTxt = "Final Total: ";
String regTxt = "Region Totals";
System.out.printf(colBld);
System.out.printf("|%-15s|%-10s|\n",regTxt,regNbr);
System.out.printf(colBld);
System.out.printf("|%s%s\n",totalTxt,totalNbr);
System.out.printf(colBld);
Here is what the code currently looks like once run:
|---------------|----------|----------|----------|----------|
|First Quarter |Region 1 |Region 2 |Region 3 |Region 4 |
|---------------|----------|----------|----------|----------|
|Product 1 |2 |10 |3 |1 |
|---------------|----------|----------|----------|----------|
|Product 2 |15 |15 |7 |16 |
|---------------|----------|----------|----------|----------|
|Product 3 |15 |13 |7 |9 |
|---------------|----------|----------|----------|----------|
|Product 4 |4 |14 |11 |11 |
|---------------|----------|----------|----------|----------|
|Region Totals |0 |
|---------------|----------|----------|----------|----------|
|Final total: 0
|---------------|----------|----------|----------|----------|
Honestly have no idea where to even begin with this. Any help is appreciated!
Since you have already sequentially filled the sales array with random Integer values to represent sequentially displayed Regions it is then a simple matter of stepping through the array elements in increments of the number of regions and summing the elements detected in each step.
To determine the actual number of Regions that will be displayed and the number of Region Totals to keep track of, we can base it from the value contained within the colNbr variable less 1 (5 - 1 = 4 regions will be displayed).
Knowing this we declare yet another integer Array named regionTotals and give it a length of 4:
int[] regionTotals = new int[colNbr-1];
Now it's a matter of stepping through the sales array elements and summing the proper sales array element to the proper regionTotal element, like this:
int regionCols = colNbr-1;
int[] regionTotals = new int[regionCols];
int stepCounter = 0;
for (int i = 0; i < sales.length; i++) {
stepCounter++;
if (stepCounter > regionCols) { stepCounter = 1; }
int regionIndex = (stepCounter - 1);
regionTotals[regionIndex]+= sales[i];
}
System.out.println("\nRegion Totals: " + Arrays.toString(regionTotals) + "\n");
Place the above code directly above the declaration & initialization of the totalNbr integer variable:
int totalNbr = 0; //Placeholder zero
How you format the regionTotals array elements into your table is up to you but do remember, the Array is zero based so the element at index 0 of the array contains the summation for Region 1.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I'm trying to write for code that searches for the first occurrence of a string (a needle) within another string (a haystack) and return the index of the first character in the matching string.
I've found the following solution online, but I'm having trouble understanding how it works. Can someone please explain to me how it functions?
private static int strStr(String needle, String haystack)
{
for (int i=0;;i++) { //
for (int j=0;;j++) {
if (j== needle.length()) return i;
if (i + j == haystack.length()) return -1;
System.out.println("needle.charAt(j) "+j+" "+needle.charAt(j));
System.out.println("haystack.charAt(i+j) "+(i+j)+" "+haystack.charAt(i+j));
if (needle.charAt(j) != haystack.charAt(i + j)) break;
}
}
}
private static int strStr(String needle, String haystack)
{
for (int i = 0 ; ; i++)
{
for (int j = 0 ; ; j++)
{
if (j == needle.length())
{
return i;
}
if (i + j == haystack.length())
{
return -1;
}
System.out.println("needle.charAt(j) " + j + " " + needle.charAt(j));
System.out.println("haystack.charAt(i+j) " + (i + j) + " " + haystack.charAt(i+j));
if (needle.charAt(j) != haystack.charAt(i + j))
{
break;
}
}
}
}
First, let's establish a few things:
Java starts indices at 0, so needle.charAt(0) is the first character in the string. needle.charAt(3) is the fourth character in the string.
The line for(int i = 0 ; ; i++) increments i by one through each iteration, and the for-loop will not cause the loop to stop.
It's easiest to tackle this with an example. Let's use a needle named "hip" and a haystack named "chips". Since Java indices start at 0, we would expect that the method will return 1 (representing the second character), since that's the first character of "hip" within "chips".
When we enter the method, we go through the first for-loop. i = 0
The next line takes us into another for-loop. i = 0, j = 0
j = 0 does not equal needle.length() = 3
i + j = 0 + 0 = 0 does not equal haystack.length() = 5
needle.charAt(j = 0) is "h", haystack.charAt(i + j = 0 + 0 = 0) is "c". Since "h" is not equal to "c", we break out of the j-for-loop. The break keyword only breaks out of the current loop, so while we stopped executing the j for-loop, we're still within the i-for-loop.
We start the next iteration. i = 1
The j for-loop restarts at 0. i = 1, j = 0
j = 0 does not equal needle.length() = 3
i + j = 1 + 0 = 1 does not equal haystack.length() = 5
needle.charAt(j = 0) is "h", haystack.charAt(i + j = 1 + 0 = 1) is "h". Since these are equal, we don't break out of the j-for-loop.
We start the next iteration of the j for-loop. i = 1, j = 1
j = 1 does not equal needle.length() = 3
i + j = 1 + 1 = 2 does not equal haystack.length() = 5
needle.charAt(j = 1) is "i", haystack.charAt(i + j = 1 + 1 = 2) is "i". Since these are equal, we don't break out of the j-for-loop.
We start the next iteration of the j for-loop. i = 1, j = 2
j = 2 does not equal needle.length() = 3
i + j = 1 + 2 = 3 does not equal haystack.length() = 5
needle.charAt(j = 2) is "p", haystack.charAt(i + j = 1 + 2) is "p". Since these are equal, we don't break out of the j-for-loop.
We start the next iteration of the j for-loop. i = 1, j = 3
j = 3 does equal needle.length() = 3, so we return i = 1.
As we expected, we got 1 back from this function, since "hip" is contained within "chips" starting at position 1 (zero-indexed).
That's all well and good, but what about that i + j == haystack.length() line?
Let's use "ben" as the needle and "bear" as the haystack (we should get back -1, since "ben" does not appear in the word "bear").
/- needle.length()
| /- haystack.length()
| | /- needle.charAt(j)
| | | /- haystack.charAt(i + j)
| | | |
i | j |n.l|h.l|n.c|h.c| result
---+---+---+---+---+---+------------------
0 | 0 | 3 | 4 | b | b | continue
0 | 1 | 3 | 4 | e | e | continue
0 | 2 | 3 | 4 | n | a | break j
1 | 0 | 3 | 4 | b | e | break j
2 | 0 | 3 | 4 | b | a | break j
3 | 0 | 3 | 4 | b | r | break j
4 | 0 | 3 | 4 | | | i + j == haystack.length(), return -1
you can use contains() or indexOf() for that.
for example:
String str1 = "This is string of words";
String str2 = "string";
int pos = str1.indexOf(str2);
in pos will int with position. Also you can add toUpperCase(), in this case search will be without letter register.
I'm trying to print my 2D array to the console as if the array were co-ordinates on a chess board for example, my code looks like this:
public Piece[][] getBoardView() throws NoBoardDefinedException
{
System.out.println(Arrays.deepToString(board));
return board;
}
This currently prints the 2D array in one straight line across the console, can anyone suggest a way to change this into a board style format?
Try this.
for (Piece[] row : board)
System.out.println(Arrays.toString(row));
if this is the case then you would get likewise,
int chessboard [][] = {
{1,2,3},
{4,5,6},
{7,8,9}
};
for(int i = 0; i < chessboard.length ; i ++){
System.out.println();
for(int j = 0 ; j < chessboard[i].length ; j++){
System.out.print(" | " + chessboard[i][j] );
}
System.out.print(" |");
System.out.println();
}
OUT PUT :
| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |
I am working on a little program to calculate and draw a parabola. But I'm stuck at a little part in the program where I need to calculate the valuetable.
The quadratic function is the following one: y = a * (x - alpha)² + Beta.
So if I fill in the following values for this function: y = 2 * (x - 1)² + (-12). I need to become this value table:
x | -4.0 | -3.0 | -2.0 | -1.0 | 0.0 | 1.0 | 2.0 | 3.0 | 4.0 |
y | 38.0 | 20.0 | 6.0 | -4.0 |-10.0|-12.0|-10.0|-4.0 | 6.0 |
I managed to get the first row right, but the second row (the one that calculates te values), is totally wrong.
public double[][] berekenWaardentabel(int input[], int AANTALKOLOMMEN, double startWaarde) {
double[][] waarden = new double[RIJEN][AANTALKOLOMMEN];
System.out.println(waarden.length);
System.out.println(startWaarde + "\n");
for(int i = 0; i < RIJEN; i++) {
for(int j = 0; j < AANTALKOLOMMEN; j++) {
waarden[0][j] = startWaarde++; //value of first row (start from -4.0, counts upwards)
waarden[1][j] = input[0] * (Math.pow((startWaarde - input[1]), 2)) + input[2];
System.out.print(waarden[i][j] + " ");
}
System.out.println();
}
return waarden;
}
This is the output I get:
-4.0 -3.0 -2.0 -1.0 0.0 1.0 2.0 3.0 4.0 5.0 6.0
86.0 | 116.0 | 150.0 | 188.0 | 230.0 | 276.0 | 326.0 | 380.0 | 438.0 | 500.0 | 566.0
Anyone an idea how to solve this problem? Thanks!
You have to mistakes :
you want to fill two lines of your array (the 0-th (x) and the first(y)). Then you store the value of x in the first row and compute y(x+1) in the second row.
you need to fill your array with :
for (int j = 0; j < AANTALKOLOMMEN; j++) {
waarden[0][j] = startWaarde; // value of first row (start from -4.0, counts upwards)
waarden[1][j] = input[0] * (Math.pow((startWaarde - input[1]), 2)) + input[2];
startWaarde++;
}
Then you can display your values :
for (int i = 0; i < 2; i++) {
for (int j = 0; j < AANTALKOLOMMEN; j++) {
System.out.print(waarden[i][j] + " ");
}
System.out.println();
}
First error is this:
waarden[0][j] = startWaarde++; //value of first row (start from -4.0, counts upwards)
waarden[1][j] = input[0] * (Math.pow((startWaarde - input[1]), 2)) + input[2];
You put the value of startWaarde in waarden[0][j]. And then you increment it by one.
Then you calculate the value of the function for the updated startWaarde.
So your waarden[0][j] is, perhaps, 4.0, but you calculate the value waarden[1][j] for 5.0 rather than 4.0.
Your other problem is that you are looping with this line:
for(int i = 0; i < RIJEN; i++) {
I don't know what the value of RIJEN is. But your waarden array is only supposed to have two rows. Once you go through the loop again and again, startWaarde keeps growing and growing. Because you print the second row only after this loop iterates the second time, you see the wrong values.
You shouldn't have this loop at all.
I just finished a program which enable to report all possible LCS and the location of the two strings respectively. However, the output of the test case isn't totally correct.
For example, if the two strings are "AACADBCDADCB" and "DCACDCBBDBAD", the correct result should report 8 cases. My output just report 6 cases, like below:
--- Output ---
Max. length = 7
LCS: ACDBDAD , in X: 2 3 5 6 8 9 10 , in Y: 3 4 5 7 9 11 12
LCS: ACDBDAD , in X: 2 3 5 6 8 9 10 , in Y: 3 4 5 8 9 11 12
LCS: ACDCDAD , in X: 2 3 5 7 8 9 10 , in Y: 3 4 5 6 9 11 12
LCS: CADBDAD , in X: 3 4 5 6 8 9 10 , in Y: 2 3 5 7 9 11 12
LCS: CADBDAD , in X: 3 4 5 6 8 9 10 , in Y: 2 3 5 8 9 11 12
LCS: CADCDAD , in X: 3 4 5 7 8 9 10 , in Y: 2 3 5 6 9 11 12
Please give me some suggestions. Pretty Thanks!
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
public class LCSMain {
//test case
private static String x = "AACADBCDADCB";
private static String y = "DCACDCBBDBAD";
private static int maxLength = 0;
private static List<String> maxNodelist = new ArrayList<String>();
private static int[][] len = null;
private static int[][] type = null;
private static TreeSet<String> outputSet = new TreeSet<String>();
public static void main (String[] args) {
len = new int[x.length()+1][y.length()+1];
type = new int[x.length()+1][y.length()+1];
dpMatrix(x,y);
//Backtrack all possible LCS and add the results into outputSet
for(int count=0; count< maxNodelist.size(); count++){
String index = maxNodelist.get(count);
String[] indexAry = index.split(",");
int i = Integer.valueOf(indexAry[0]);
int j = Integer.valueOf(indexAry[1]);
ArrayList<ArrayList<String>> list = backTrack(x, y, i, j);
for(int counter=0; counter<list.get(0).size(); counter++){
outputSet.add(list.get(0).get(counter) +"," + list.get(1).get(counter) + "," + list.get(2).get(counter));
}
}
//Print all possible results
System.out.println("--- Output ---");
System.out.println("Max. length = " + len[x.length()][y.length()]);
for(String s: outputSet){
String[] ary = s.split(",");
System.out.println("LCS: " + ary[0] + " , in X: " + ary[1] + " , in Y: " + ary[2]);
}
}
/**
* Set the DP matrix
**/
private static void dpMatrix(String s1, String s2) {
for (int i = 1; i <=s1.length(); i++) {
for (int j = 1; j <=s2.length(); j++) {
if (s1.charAt(i-1) == s2.charAt(j-1)) {
len[i][j] = len[i-1][j-1] + 1;
type[i][j] = 1;
}else{
if(len[i-1][j] != len[i][j-1]){
if(len[i-1][j] > len[i][j-1]){
len[i][j] = len[i-1][j];
type[i][j] = 2;
}else{
len[i][j] = len[i][j-1];
type[i][j] = 3;
}
}else{
//if equal, set is as case 4
len[i][j] = len[i][j-1];
type[i][j] = 4;
}
}
if(len[i][j] > maxLength){
maxNodelist.clear();
maxLength = len[i][j];
maxNodelist.add(i + "," + j);
}else if(len[i][j] == maxLength){
maxNodelist.add(i + "," + j);
}
}// End of for
}// End of for
}
/**
* Backtrack from (i, j). Find out LCS and record the location of the strings respectively
* #param s1 1st string
* #param s2 2nd string
* #param i row index in the matrix
* #param j column index in the matrix
* #return ArrayList<ArrayList<String>>, outer ArrayList collect three inner ArrayList in order: LCS string, 1st string LCS location, 2nd string LCS location
*/
private static ArrayList<ArrayList<String>> backTrack(String s1, String s2, int i, int j){
if (i == 0 || j == 0) {
ArrayList<ArrayList<String>> list = new ArrayList<ArrayList<String>>();
ArrayList<String> lcsList = new ArrayList<String>();
ArrayList<String> xList = new ArrayList<String>();
ArrayList<String> yList = new ArrayList<String>();
lcsList.add("");
xList.add("");
yList.add("");
list.add(lcsList);
list.add(xList);
list.add(yList);
return list;
}
if(type[i][j]==1){
ArrayList<ArrayList<String>> resultList = new ArrayList<ArrayList<String>>();
ArrayList<String> resultLcsList = new ArrayList<String>();
ArrayList<String> resultXList = new ArrayList<String>();
ArrayList<String> resultYList = new ArrayList<String>();
ArrayList<ArrayList<String>> list = backTrack(s1, s2, i - 1, j - 1);
ArrayList<String> lcsList = list.get(0);
ArrayList<String> xList = list.get(1);
ArrayList<String> yList = list.get(2);
for(String s: lcsList){
resultLcsList.add(s + s1.charAt(i - 1));
}
for(String s: xList){
resultXList.add(s + " " + i);
}
for(String s: yList){
resultYList.add(s + " " + j);
}
resultList.add(resultLcsList);
resultList.add(resultXList);
resultList.add(resultYList);
return resultList;
}else if(type[i][j]==2){
ArrayList<ArrayList<String>> list = backTrack(s1,s2, i-1, j);
return list;
}else if(type[i][j]==3){
ArrayList<ArrayList<String>> list = backTrack(s1,s2, i, j-1);
return list;
}else{
ArrayList<ArrayList<String>> list = new ArrayList<ArrayList<String>>();
list = backTrack(s1,s2, i-1, j);
ArrayList<ArrayList<String>> case3list = backTrack(s1,s2, i, j-1);
ArrayList<String> lcsList = list.get(0);
ArrayList<String> xList = list.get(1);
ArrayList<String> yList = list.get(2);
lcsList.addAll(case3list.get(0));
xList.addAll(case3list.get(1));
yList.addAll(case3list.get(2));
list.set(0, lcsList);
list.set(1, xList);
list.set(2, yList);
return list;
}
}
}
I've updated your code to visualize the snakes (path of the LCS found), to use the interface type of List instead of the concrete object ArrayList and gave the direction values a bit more meaning by utilizing an enumeration instead of an int value.
It may not be the best code I've ever written but it does the job of visualizing the snakes found:
package lcs;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
/**
* <p>
* Longest common subsequecne finds the longest subsequence common to all
* sequences in a set of sequences. A subsequence in contrast to a substring
* does not have to consist of consecutive terms.
* </p>
*/
public class LCSMain
{
//test case
private static String x = "AACADBCDADCB";
private static String y = "DCACDCBBDBAD";
/** The maximum length of the longest common subsequences found **/
private static int maxLength = 0;
/** will hold a reference to the (i,j) nodes with match the length of the
* longest common subsequence **/
private static List<String> maxNodelist = new ArrayList<>();
/** will hold a form of heightfield that indicates the length of a
* subsequence which is reachable from this position **/
private static int[][] len = null;
/** will hold the direction values to backtrack the longest common
* subsequences **/
private static Direction[][] type = null;
private static TreeSet<String> outputSet = new TreeSet<>();
/**
* <p>
* Entrance point for the application. It will find the longest common
* subsequences (LCS) between <em>AACADBCDADCB</em> and <em>DCACDCBBDBAD</em>
* and print a graphical representation of the snakes (=path for a LCS) found
* as well as a listing of the found LCS and their positions within the
* original strings.
* </p>
*
* #param args The arguments passed to the application. Unused.
*/
public static void main (String[] args)
{
len = new int[x.length()+1][y.length()+1];
type = new Direction[x.length()+1][y.length()+1];
dpMatrix(x,y);
//Backtrack all possible LCS and add the results into outputSet
for(int count=0; count< maxNodelist.size(); count++)
{
String index = maxNodelist.get(count);
String[] indexAry = index.split(",");
int i = Integer.valueOf(indexAry[0]);
int j = Integer.valueOf(indexAry[1]);
List<List<String>> list = backTrack(x, y, i, j);
for(int counter=0; counter<list.get(0).size(); counter++)
{
outputSet.add(list.get(0).get(counter) +","
+ list.get(1).get(counter) + ","
+ list.get(2).get(counter));
}
}
// visualize the maximum length of a longest common subsequence
// accessible from any point in the matrix
printHeightField();
// visualize the path's found for the longest common subsequences
printSnake();
//Print all possible results
System.out.println("--- Output ---");
System.out.println("Max. length = " + len[x.length()][y.length()]);
for(String s: outputSet)
{
String[] ary = s.split(",");
System.out.println("LCS: " + ary[0] + ", in X: "
+ ary[1] + ", in Y: " + ary[2]);
}
}
/**
* <p>
* Prints the different subsequences into a matrix which contains the
* calculated direction values.
* </p>
*/
private static void printSnake()
{
// fill a char matrix with direction values
char[][] matrix = createDirectionMatrix();
// add path information to the matrix
for (String node : maxNodelist)
{
String[] indexAry = node.split(",");
int i = Integer.valueOf(indexAry[0]);
int j = Integer.valueOf(indexAry[1]);
backtrackPath(matrix, i, j);
}
// print the matrix
System.out.println("Snakes:");
System.out.println(printMatrix(matrix));
}
/**
* <p>
* Adds backtracking information to the direction matrix.
* </p>
*
* #param matrix The matrix to update with path informations
* #param i row index in the type matrix
* #param j column index in the type matrix
*/
private static void backtrackPath(char[][] matrix, int i, int j)
{
if (i==0 || j==0)
return;
// convert the index to matrix coordinates
int line = j*2+2;
int col = i*2+3;
// check which direction we need to follow
if (Direction.EQUALS.equals(type[i][j]))
{
matrix[line-1][col-1] = '\\';
backtrackPath(matrix, i-1, j-1);
}
else if (Direction.LEFT.equals(type[i][j]))
{
matrix[line][col-1] = '-';
backtrackPath(matrix, i-1, j);
}
else if (Direction.TOP.equals(type[i][j]))
{
matrix[line-1][col] = '|';
backtrackPath(matrix, i, j-1);
}
else
{
// split the path in both direction: to the left and to the top
matrix[line][col-1] = '-';
backtrackPath(matrix, i-1, j);
matrix[line-1][col] = '|';
backtrackPath(matrix, i, j-1);
}
}
/**
* <p>
* Creates an output matrix for the specified words containing the direction
* values as matrix data.
* </p>
*
* #return The created matrix containing direction values for the longest
* common subsequences
*/
private static char[][] createDirectionMatrix()
{
char[][] matrix = new char[2+type.length*2-1][];
for (int i=0; i<matrix.length; i++)
matrix[i] = new char[2+type.length*2];
// build the output matrix
for (int line=0; line<matrix.length; line++)
{
// The header column
if (line == 0)
{
for (int col = 0; col < matrix[line].length; col++)
{
if (col == 3)
matrix[line][col] = '^';
else if (col == 1)
matrix[line][col] = '|';
// empty column
else if (col % 2 == 0)
matrix[line][col] = ' ';
else if (col > 4)
{
matrix[line][col] = x.charAt(col / 2 - 2);
}
}
}
else if (line == 1)
{
for (int col = 0; col < matrix[line].length; col++)
{
if (col == 1)
matrix[line][col] = '+';
else
matrix[line][col] = '-';
}
}
// empty line
else if (line % 2 != 0)
{
for (int col = 0; col < matrix[line].length; col++)
{
if (col == 1)
matrix[line][col] = '|';
else
matrix[line][col] = ' ';
}
}
// border-line - 0 values, ^ indicates the start of the word
else if (line == 2)
{
for (int col = 0; col < matrix[line].length; col++)
{
if (col == 0)
matrix[line][col] = '^';
else if (col == 1)
matrix[line][col] = '|';
else if (col % 2 == 0)
matrix[line][col] = ' ';
else if (col > 2)
matrix[line][col] = '0';
}
}
// first column is the letter of the second word followed by
// space, delimiter, a further space and the direction value
else
{
for (int col = 0; col < matrix[line].length; col++)
{
if (col == 0)
{
char c = y.charAt(line/2-2);
matrix[line][col] = c;
}
else if (col == 1)
matrix[line][col] = '|';
else if (col == 3)
matrix[line][col] = '0';
else if (col % 2 == 0)
matrix[line][col] = ' ';
else
{
int val = type[col/2-2+1][line/2-2+1].getValue();
matrix[line][col] = (char)('0'+val);
}
}
}
}
return matrix;
}
/**
* <p>
* Prints the content of the matrix containing the length values. The output
* will contain a heightmap like structure containing isoquants indicating
* the area where all subsequences have the same length.
* </p>
*/
private static void printHeightField()
{
System.out.println("Height-Field:");
System.out.println(printMatrix(createLengthMatrix()));
}
/**
* <p>
* Creates an output matrix for the specified words containing length values
* for each character couple. The specific value of each character couple
* marks the length of a subsequence which is reachable from this position.
* </p>
*
* #return
*/
private static char[][] createLengthMatrix()
{
char[][] matrix = new char[2+type.length*2-1][];
for (int i=0; i<matrix.length; i++)
matrix[i] = new char[2+type.length*2];
// build the output matrix
for (int line=0; line<matrix.length; line++)
{
// The header column
if (line == 0)
{
for (int col = 0; col < matrix[line].length; col++)
{
if (col == 3)
matrix[line][col] = '^';
else if (col == 1)
matrix[line][col] = '|';
// empty column
else if (col % 2 == 0)
matrix[line][col] = ' ';
else if (col > 4)
{
matrix[line][col] = x.charAt(col / 2 - 2);
}
}
}
else if (line == 1)
{
for (int col = 0; col < matrix[line].length; col++)
{
if (col == 1)
matrix[line][col] = '+';
else
matrix[line][col] = '-';
}
}
// empty line
else if (line % 2 != 0)
{
for (int col = 0; col < matrix[line].length; col++)
{
if (col == 1)
matrix[line][col] = '|';
else
{
matrix[line][col] = ' ';
}
}
}
// border-line - 0 values, ^ indicates the start of the word
else if (line == 2)
{
for (int col = 0; col < matrix[line].length; col++)
{
if (col == 0)
matrix[line][col] = '^';
else if (col == 1)
matrix[line][col] = '|';
else if (col % 2 == 0)
matrix[line][col] = ' ';
else if (col > 2)
matrix[line][col] = '0';
}
}
// first column is the letter of the second word followed by
// space, delimiter, a further space and the direction value
else
{
for (int col = 0; col < matrix[line].length; col++)
{
if (col == 0)
{
char c = y.charAt(line/2-2);
matrix[line][col] = c;
}
else if (col == 1)
matrix[line][col] = '|';
else if (col == 3)
matrix[line][col] = '0';
else if (col % 2 == 0)
{
// check if the char to the left and to the top are
// delimiters, if so close it
if (matrix[line-2][col] == '|'
&& matrix[line-1][col-1] == '-')
matrix[line-1][col] = '+';
else
matrix[line][col] = ' ';
}
else
{
int x = col/2-2+1;
int y = line/2-2+1;
int val = len[x][y];
// check if the value to the left is lower than the
// actual value - insert a separator if so
if (x > 0)
{
if (len[x-1][y] < val)
{
// as we only write the length values every
// second line we need to fill the previous line
// too, else we have a gap in between
matrix[line-1][col-1] = '|';
matrix[line][col-1] = '|';
}
}
// check if the value to the top is lower than the
// actual value - insert a separator if so
if (y > 0)
{
if (len[x][y-1] < val)
{
// as we only write the length values every
// second column we need to fill the previous
// column too, else we have a gap in between
matrix[line-1][col] = '-';
matrix[line-1][col-1] = '-';
}
}
// connect left and top separators
if (matrix[line-1][col] == '-'
&& matrix[line][col-1] == '|')
matrix[line-1][col-1] = '+';
matrix[line][col] = (char)('0'+val);
}
}
}
}
return matrix;
}
/**
* <p>
* Returns the content of the direction matrix as a single {#link String}.
* </p>
*
* #param matrix The matrix to convert to String
* #return The String containing the direction values for the longest common
* subsequences
*/
private static String printMatrix(char[][] matrix)
{
StringBuilder sb = new StringBuilder();
for (int line = 0; line < matrix.length; line++)
{
for (int col = 0; col < matrix[line].length; col++)
{
sb.append(matrix[line][col]);
}
sb.append("\n");
}
return sb.toString();
}
/**
* Set the DP matrix
*
* <p>
* Fills two matrices and a list of nodes that achieved the maximum length
* for subsequences. The first matrix, <code>len</code> contains the maximum
* length a subsequence can achieve for each position. The second matrix,
* <code>type</code>, contains a direction pointer for backtracking.
* </p>
* <p>
* The filed list of nodes will contain the end nodes which achieved the
* greatest length value for a subsequence.
* </p>
*
* #param s1 The first string
* #param s2 The second string
**/
private static void dpMatrix(String s1, String s2)
{
for (int i = 1; i <= s1.length(); i++)
{
for (int j = 1; j <= s2.length(); j++)
{
// check if the characters match
if (s1.charAt(i-1) == s2.charAt(j-1))
{
len[i][j] = len[i-1][j-1] + 1;
type[i][j] = Direction.EQUALS;
}
else
{
// no match
// check if the value to the left is larger then the
// value to the top
if(len[i-1][j] > len[i][j-1])
{
len[i][j] = len[i-1][j];
type[i][j] = Direction.LEFT;
}
// is value to the top larger than the left one?
else if (len[i-1][j] < len[i][j-1])
{
len[i][j] = len[i][j-1];
type[i][j] = Direction.TOP;
}
else
{
// both values, the left one and the top one are
// identical so it does not matter which value we are
// taking later on
len[i][j] = len[i][j-1];
type[i][j] = Direction.SPLIT;
}
}
// save the end-nodes that achieve the longest commong
// subsequence
if(len[i][j] > maxLength)
{
maxNodelist.clear();
maxLength = len[i][j];
maxNodelist.add(i + "," + j);
}
else if(len[i][j] == maxLength)
{
maxNodelist.add(i + "," + j);
}
}// End of for
}// End of for
}
/**
* <p>
* Backtrack from (i, j). Find out LCS and record the location of the
* strings respectively
* </p>
*
* #param s1 1st string
* #param s2 2nd string
* #param i row index in the matrix
* #param j column index in the matrix
* #return List<List<String>>, outer List collect three inner List in order:
* LCS string, 1st string LCS location, 2nd string LCS location
*/
private static List<List<String>> backTrack(String s1, String s2, int i, int j)
{
if (i == 0 || j == 0)
{
List<List<String>> list = new ArrayList<>();
List<String> lcsList = new ArrayList<>();
List<String> xList = new ArrayList<>();
List<String> yList = new ArrayList<>();
lcsList.add("");
xList.add("");
yList.add("");
list.add(lcsList);
list.add(xList);
list.add(yList);
return list;
}
if(Direction.EQUALS.equals(type[i][j]))
{
List<List<String>> resultList = new ArrayList<>();
List<String> resultLcsList = new ArrayList<>();
List<String> resultXList = new ArrayList<>();
List<String> resultYList = new ArrayList<>();
List<List<String>> list = backTrack(s1, s2, i - 1, j - 1);
List<String> lcsList = list.get(0);
List<String> xList = list.get(1);
List<String> yList = list.get(2);
for(String s: lcsList)
{
resultLcsList.add(s + s1.charAt(i - 1));
}
for(String s: xList)
{
resultXList.add(s + " " + i);
}
for(String s: yList)
{
resultYList.add(s + " " + j);
}
resultList.add(resultLcsList);
resultList.add(resultXList);
resultList.add(resultYList);
return resultList;
}
else if(Direction.LEFT.equals(type[i][j]))
{
List<List<String>> list = backTrack(s1, s2, i-1, j);
return list;
}
else if(Direction.TOP.equals(type[i][j]))
{
List<List<String>> list = backTrack(s1, s2, i, j-1);
return list;
}
else
{
// backtrack to the left
List<List<String>> leftMove = backTrack(s1, s2, i-1, j);
// backtrack to the top
List<List<String>> topMove = backTrack(s1, s2, i, j-1);
List<String> lcsList = leftMove.get(0);
List<String> xList = leftMove.get(1);
List<String> yList = leftMove.get(2);
lcsList.addAll(topMove.get(0));
xList.addAll(topMove.get(1));
yList.addAll(topMove.get(2));
return leftMove;
}
}
}
And the added enumeration to give the directions a bit more semantics:
package lcs;
/**
* <p>
* Enumeration of the possible direction for backtracking.
* </p>
*/
public enum Direction
{
/** will result in a single move to the top as well as to the left **/
EQUALS(1),
/** will result in a move to the left **/
LEFT(2),
/** will result in a move to the top **/
TOP(3),
/** will result in splitting the move to follow both directions at once:
* to the left and to the top **/
SPLIT(4);
/** will hold an int value representing the defined direction **/
private final int value;
/**
* <p>
* Initializes the enumeration value with an int-value.
* </p>
*
* #param value The int value to assign to the enumeration value
*/
private Direction(int value)
{
this.value = value;
}
/**
* <p>
* Returns the int representation of the corresponding enumeration.
* </p>
*
* #return The int value of this enumeration value
*/
public int getValue()
{
return this.value;
}
}
Executing this application will result in the following output:
Height-Field:
| ^ A A C A D B C D A D C B
-+--------------------------
^| 0 0 0 0 0 0 0 0 0 0 0 0 0
| +---------------
D| 0 0 0 0 0|1 1 1 1 1 1 1 1
| +---+ +-----------
C| 0 0 0|1 1 1 1|2 2 2 2 2 2
| +---+ +-----+ +-------
A| 0|1 1 1|2 2 2 2 2|3 3 3 3
| | +-+ +---+ +---
C| 0|1 1|2 2 2 2|3 3 3 3|4 4
| | | +---+ +-----+
D| 0|1 1|2 2|3 3 3|4 4 4 4 4
| | | | +-+ +---
C| 0|1 1|2 2|3 3|4 4 4 4|5 5
| | | | +-+ | +-
B| 0|1 1|2 2|3|4 4 4 4 4|5|6
| | | | | | |
B| 0|1 1|2 2|3|4 4 4 4 4|5|6
| | | | | +-----+ |
D| 0|1 1|2 2|3|4 4|5 5 5 5|6
| | | | | | |
B| 0|1 1|2 2|3|4 4|5 5 5 5|6
| | +-+ +-+ | | +-----+
A| 0|1|2 2|3 4|4 4|5|6 6 6 6
| | | | +-+ | | +-----
D| 0|1|2 2|3|4 4 4|5|6|7 7 7
Snakes:
| ^ A A C A D B C D A D C B
-+--------------------------
^| 0 0 0 0 0 0 0 0 0 0 0 0 0
| | |
D| 0-4-4 4 4 1 2 2 1 2 1 2 2
| | \
C| 0-4 4 1 2 4 4 1 2 2 2 1 2
| \ \
A| 0 1 1 4 1 2 2 4 4 1 2 2 2
| \ |
C| 0 3 4 1-4 4 4 1 2 4 4 1 2
| \
D| 0 3 4 3 4 1-2 4 1 2 1 4 4
| | \
C| 0 3 4 1 4 3 4 1 4 4 4 1 2
| |\ |
B| 0 3 4 3 4 3 1-4 4 4 4 3 1
| \ |
B| 0 3 4 3 4 3 1-4 4 4 4 3 1
| \
D| 0 3 4 3 4 1 3 4 1 2 1 4 3
| |
B| 0 3 4 3 4 3 1 4 3 4 4 4 1
| \
A| 0 1 1 4 1 4 3 4 3 1 2 2 4
| \
D| 0 3 3 4 3 1 4 4 1 3 1-2-2
--- Output ---
Max. length = 7
LCS: ACDBDAD, in X: 2 3 5 6 8 9 10, in Y: 3 4 5 7 9 11 12
LCS: ACDBDAD, in X: 2 3 5 6 8 9 10, in Y: 3 4 5 8 9 11 12
LCS: ACDCDAD, in X: 2 3 5 7 8 9 10, in Y: 3 4 5 6 9 11 12
LCS: CADBDAD, in X: 3 4 5 6 8 9 10, in Y: 2 3 5 7 9 11 12
LCS: CADBDAD, in X: 3 4 5 6 8 9 10, in Y: 2 3 5 8 9 11 12
LCS: CADCDAD, in X: 3 4 5 7 8 9 10, in Y: 2 3 5 6 9 11 12
So to me 6 solutions seem pretty plausible. As already mentioned in my comment, please post your 2 missing solutions so we may evaluate if either they are wrong or why they don't appear within the results of your dpMatrix() method.