Сообщите обо всех длинных общих подпоследовательностях (LCS) и их адаптивном расположении в двух строках
Я только что закончил программу, которая позволяет сообщать обо всех возможных LCS и местоположении двух строк соответственно. Тем не менее, результат теста не совсем правильно.
Например, если две строки - "AACADBCDADCB" и "DCACDCBBDBAD", правильный результат должен содержать 8 случаев. Мой вывод просто сообщить о 6 случаях, как показано ниже:
--- Выход --- Макс. длина = 7
LCS: ACDBDAD, в X: 2 3 5 6 8 9 10, в Y: 3 4 5 7 9 11 12
LCS: ACDBDAD, в X: 2 3 5 6 8 9 10, в Y: 3 4 5 8 9 11 12
LCS: ACDCDAD, в X: 2 3 5 7 8 9 10, в Y: 3 4 5 6 9 11 12
LCS: CADBDAD, в X: 3 4 5 6 8 9 10, в Y: 2 3 5 7 9 11 12
LCS: CADBDAD, в X: 3 4 5 6 8 9 10, в Y: 2 3 5 8 9 11 12
LCS: CADCDAD, в X: 3 4 5 7 8 9 10, в Y: 2 3 5 6 9 11 12
Пожалуйста, дайте мне несколько предложений. Довольно Спасибо!
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;
}
}
}
1 ответ
Я обновил ваш код для визуализации змей (путь к найденному LCS), чтобы использовать тип интерфейса List
вместо конкретного объекта ArrayList
и придал значениям направления немного больше смысла, используя перечисление вместо значения int.
Возможно, это не лучший код, который я когда-либо писал, но он выполняет работу по визуализации найденных змей:
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;
}
}
}
И добавленное перечисление, чтобы дать направлениям немного больше семантики:
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;
}
}
Выполнение этого приложения приведет к следующему выводу:
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
Так что 6 решений кажутся мне вполне правдоподобными. Как уже упоминалось в моем комментарии, пожалуйста, опубликуйте свои 2 отсутствующих решения, чтобы мы могли оценить, являются ли они ошибочными или почему они не появляются в результатах вашего dpMatrix()
метод.