含通配符0的二维整数数组非精确模式搜索算法咨询
带通配符的二维数组模式匹配算法
当然存在这样的算法,下面提供两种实现思路,优先给出Java代码:
一、暴力匹配法(简单直接,适合小规模数组)
核心思路是遍历T中所有可能的起始位置,逐个元素比对:当P中的元素是0时直接判定匹配成功,否则检查T对应位置的元素是否与P相等。
Java实现
import java.util.ArrayList; import java.util.List; public class PatternMatch { // 存储匹配位置的内部类 static class Position { int row; int col; public Position(int row, int col) { this.row = row; this.col = col; } @Override public String toString() { return "(" + row + ", " + col + ")"; } } public static List<Position> findMatches(int[][] T, int[][] P) { List<Position> matches = new ArrayList<>(); int m = T.length; int n = T[0].length; int u = P.length; int v = P[0].length; // 遍历所有可能的起始行 for (int i = 0; i <= m - u; i++) { // 遍历所有可能的起始列 for (int j = 0; j <= n - v; j++) { boolean isMatch = true; // 逐元素比对模式和子数组 for (int x = 0; x < u; x++) { for (int y = 0; y < v; y++) { int pVal = P[x][y]; if (pVal != 0 && T[i + x][j + y] != pVal) { isMatch = false; break; } } if (!isMatch) break; } if (isMatch) { matches.add(new Position(i, j)); } } } return matches; } public static void main(String[] args) { int[][] T = { {2, 3, 4, 3, 6}, {4, 1, 5, 7, 8}, {9, 1, 2, 3, 1}, {2, 4, 5, 1, 5}, {3, 1, 9, 0, 2} }; int[][] P = { {2, 3, 0}, {0, 1, 5}, {9, 0, 2} }; List<Position> result = findMatches(T, P); System.out.println("匹配位置:"); for (Position pos : result) { System.out.println(pos); } } }
二、改进的Rabin-Karp算法(高效,适合大规模数组)
原Rabin-Karp算法通过哈希值快速排除不匹配的子数组,这里针对通配符需求修改哈希逻辑:仅计算P中非0元素的哈希值,比对时只验证这些位置,减少无效计算。
核心改进点
- 预处理模式P,记录所有非0元素的相对位置和值,计算这些元素的加权哈希总和。
- 对T中每个候选子数组,计算对应位置的哈希值,与P的哈希值比对;哈希匹配时再逐个验证非0元素,避免哈希碰撞导致的误判。
Java实现
import java.util.ArrayList; import java.util.List; public class RabinKarpWildcard { static class Position { int row; int col; public Position(int row, int col) { this.row = row; this.col = col; } @Override public String toString() { return "(" + row + ", " + col + ")"; } } // 存储模式中非0元素的相对位置和值 static class PatternElement { int dx; int dy; int val; public PatternElement(int dx, int dy, int val) { this.dx = dx; this.dy = dy; this.val = val; } } public static List<Position> findMatches(int[][] T, int[][] P) { List<Position> matches = new ArrayList<>(); int m = T.length; int n = T[0].length; int u = P.length; int v = P[0].length; // 预处理模式,收集所有非0元素并计算哈希 List<PatternElement> patternElements = new ArrayList<>(); long patternHash = 0; final int BASE = 1000003; // 大质数作为哈希基数 final long MOD = 1000000007; // 取模避免数值溢出 for (int x = 0; x < u; x++) { for (int y = 0; y < v; y++) { int val = P[x][y]; if (val != 0) { patternElements.add(new PatternElement(x, y, val)); // 计算加权哈希值 long weight = pow(BASE, x * v + y, MOD); patternHash = (patternHash + val * weight) % MOD; } } } // 模式全为0时,所有合法起始位置都匹配 if (patternElements.isEmpty()) { for (int i = 0; i <= m - u; i++) { for (int j = 0; j <= n - v; j++) { matches.add(new Position(i, j)); } } return matches; } // 遍历T中所有可能的起始位置 for (int i = 0; i <= m - u; i++) { for (int j = 0; j <= n - v; j++) { // 计算当前子数组的哈希值 long currentHash = 0; for (PatternElement elem : patternElements) { int tx = i + elem.dx; int ty = j + elem.dy; long weight = pow(BASE, elem.dx * v + elem.dy, MOD); currentHash = (currentHash + T[tx][ty] * weight) % MOD; } // 哈希匹配时,逐个验证避免碰撞 if (currentHash == patternHash) { boolean isMatch = true; for (PatternElement elem : patternElements) { int tx = i + elem.dx; int ty = j + elem.dy; if (T[tx][ty] != elem.val) { isMatch = false; break; } } if (isMatch) { matches.add(new Position(i, j)); } } } } return matches; } // 快速幂计算:base^exponent mod modVal private static long pow(long base, int exponent, long modVal) { long result = 1; base = base % modVal; while (exponent > 0) { if (exponent % 2 == 1) { result = (result * base) % modVal; } exponent = exponent >> 1; base = (base * base) % modVal; } return result; } public static void main(String[] args) { int[][] T = { {2, 3, 4, 3, 6}, {4, 1, 5, 7, 8}, {9, 1, 2, 3, 1}, {2, 4, 5, 1, 5}, {3, 1, 9, 0, 2} }; int[][] P = { {2, 3, 0}, {0, 1, 5}, {9, 0, 2} }; List<Position> result = findMatches(T, P); System.out.println("匹配位置:"); for (Position pos : result) { System.out.println(pos); } } }
说明
- 暴力匹配法实现简单,时间复杂度为O(mnuv),适合小规模数组场景。
- 改进的Rabin-Karp算法通过哈希预过滤,平均时间复杂度可降低至O(mn + uv),最坏情况下仍为O(mnuv),但实际运行效率远高于暴力法,适合大规模数组。
- 两种实现均能正确处理示例中的情况,返回
(0,0)和(2,2)两个匹配位置。
内容的提问来源于stack exchange,提问作者gi0rn0
相关产品推荐
相关产品推荐

