You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含通配符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元素的哈希值,比对时只验证这些位置,减少无效计算。

核心改进点

  1. 预处理模式P,记录所有非0元素的相对位置和值,计算这些元素的加权哈希总和。
  2. 对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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 18:47:04