java 查找给定矩阵的子矩阵
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9885147/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Finding sub matrix of a given matrix
提问by Ashwani Kumar
i am trying to write an algorithm for finding a sub matrix in a given sub matrix. To solve this problem i had written the following code:
我正在尝试编写一种算法,用于在给定的子矩阵中查找子矩阵。为了解决这个问题,我编写了以下代码:
public class SubMatTry {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[][] = { { 2, 3, 5, 7 }, { 5, 8, 3, 5 }, { 7, 6, 9, 2 },
{ 3, 8, 5, 9 } };
int b[][] = { { 9, 2 }, { 5, 9 } };
int k = 0;
int l = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
System.out.println("Element of a= " + a[i][j]);
if (b[k][l] == a[i][j]) {
System.out.println(b[k][l] + " = " + a[i][j]);
if (b[k][l + 1] == a[i][j + 1]) {
System.out.println(b[k][l + 1] + " = " + a[i][j + 1]);
if (b[k + 1][l] == a[i + 1][j]) {
System.out.println(b[k + 1][l] + " = "
+ a[i + 1][j]);
if (b[k + 1][l + 1] == a[i + 1][j + 1]) {
System.out.println(b[k + 1][l + 1] + " = "
+ a[i + 1][j + 1]);
System.out.println("Array found at" + i + " ,"
+ j);
System.exit(0);
}
}
}
}
}
}
}}
This code is working fine but i am not sure it is the exact solution of the problem or its just a work around. Please provide your expert comments. Thanks in advance.
这段代码工作正常,但我不确定它是问题的确切解决方案还是只是一种解决方法。请提供您的专家意见。提前致谢。
回答by aioobe
The algorithm is hard-coded for a 4×4 matrix and a 2×2 submatrix. Otherwise it looks fine as a brute-force algorithm.
该算法针对 4×4 矩阵和 2×2 子矩阵进行了硬编码。否则它看起来很好作为一个蛮力算法。
I would have expressed it as follows:
我会表达如下:
outerRow:
for (int or = 0; or <= a.length - b.length; or++) {
outerCol:
for (int oc = 0; oc <= a[or].length - b[0].length; oc++) {
for (int ir = 0; ir < b.length; ir++)
for (int ic = 0; ic < b[ir].length; ic++)
if (a[or + ir][oc + ic] != b[ir][ic])
continue outerCol;
System.out.println("Submatrix found at row " + or + ", col " + oc);
break outerRow;
}
}
If you want something more efficient, I suggest you flatten them out, like this:
如果你想要更有效的东西,我建议你把它们弄平,像这样:
{ 2,3,5,7, 5,8,3,5, 7,6,9,2, 3,8,5,9 }
and search this sequence for the following pattern:
并在此序列中搜索以下模式:
{ 9,2, _, _, 5, 9}
using standard find-substring techniques such as Aho-Corasickor Knuth-Morris-Pratt algorithm. (Note that you would have to skip some indexes to avoid false positives where there's a new row in the middle of the sequence.)
使用标准的查找子串技术,例如Aho-Corasick或Knuth-Morris-Pratt 算法。(请注意,您必须跳过一些索引,以避免在序列中间有新行的情况下出现误报。)
回答by r3mbol
First of all, i and j should not iterate up to 3 (if you are on a[3][3] you know it can't be a start of a submatrix, cause basically you're at the end of the matrix).
首先, i 和 j 不应该迭代到 3 (如果你在 a[3][3] 你知道它不能是子矩阵的开始,因为基本上你在矩阵的末尾) .
Secondly, don't use fixed numbers, like 4 - use a.length instead (this gives you length of array a - number of columns, while a[0].length would give you a length of first column - effectively, number of rows).
其次,不要使用固定数字,比如 4 - 使用 a.length 代替(这给你数组的长度 a - 列数,而 a[0].length 会给你第一列的长度 - 实际上,数量行)。
Thirdly, I'd change the quadruple if
(sic) into a double for
iterating on k and l, like that:
第三,我将四元组if
(sic)更改为for
对 k 和 l进行双重迭代,如下所示:
for (int i = 0; i < a.length - b.length + 1; i++) {
for (int j = 0; j < a[0].length - b[0].length + 1; j++) {
boolean submatrix = true; // at start we assume we have a submatrix
for (int k = 0; k < b.length; ++k) {
for (int l = 0; l < b[0].length; ++l) {
if (a[i + k][j + l] == b[k][l]) {
System.out.println("a[" + (i + k) + "][" + (j + l) + "] = b[" + k + "][" + l + "]");
} else {
submatrix = false; // we found inequality, so it's not a submatrix
}
}
}
if (submatrix) {
System.out.println("Found subatrix at " + i + "," + j + ".");
}
}
}
(Not sure if it exactly works, didn't put it through compiler ;) )
(不确定它是否完全有效,没有通过编译器;))
Other than that if you use java, you should try to get used to objects, classes and methods (Matrix
class with boolean isSubmatrix(Matrix b)
method) - but for starters that should do.
除此之外,如果你使用 java,你应该尝试习惯对象、类和方法(Matrix
类和boolean isSubmatrix(Matrix b)
方法)——但对于初学者来说应该这样做。
Hope my answer helps.
希望我的回答有帮助。
回答by Adam Bronfin
What follows is a solution I wrote based off the described strategy by @aioobe
以下是我根据@aioobe 所描述的策略编写的解决方案
public static boolean matrixContainsPattern(int[][] data, int[][] pattern) {
int[] flatData = flattenMatrix(data);
int[] flatPattern = flattenMatrix(pattern);
//If the # of rows of data is less than the rows of pattern, we have a problem since we can match at most only a partial amount of the pattern into data
if (flatData.length < flatPattern.length) {
throw new IllegalArgumentException();
}
int dataRowLen = data[0].length;
int patternRowLen = pattern[0].length;
for (int i = 0; i < flatData.length - flatPattern.length + 1; i++) {
//We found a potential match for the pattern
if (flatData[i] == flatPattern[0]) {
//k can keep track of indexes inside flatData
int k = i;
//l can keep track of indexes inside flatPattern
int l = 0;
//dataRowOffset will help us keep track of WHERE we found a match in flatPatterns' imaginary rows
int dataRowOffset = (i % dataRowLen);
//count to keep track of when we've reached the end of an imaginary row in data
int count = 1;
boolean patternFound = true;
while (k < flatData.length && l < flatPattern.length) {
if (flatData[k] != flatPattern[l]) {
patternFound = false;
break;
}
//if we reached the end of an imaginary row, we need to skip our pointer k to the next rows offset location
//we also need to reset count to the offset, so we can again find the end of this new imaginary row
if (count == patternRowLen) {
//To get to the position in the next row of where we first found our match, we add to k: the length of whats remaining in our current row,
//plus the offset from where we first found in the match in the current row
if (dataRowLen == patternRowLen) {
k++;
} else {
k += (dataRowLen - patternRowLen) + dataRowOffset;
}
count = 1;
} else {
k++;
count++;
}
l++;
}
if (patternFound) {
return true;
}
}
}
return false;
}
And the method to flatten a matrix into an array is as follows:
将矩阵展平为数组的方法如下:
private static int[] flattenMatrix(int[][] matrix) {
if (matrix == null || matrix[0] == null || matrix[0].length < 1) {
throw new IllegalArgumentException();
}
int[] flattened = new int[matrix.length * matrix[0].length];
int k = 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
flattened[k] = matrix[i][j];
k++;
}
}
return flattened;
}