Search code examples
pythonmatrixnp

Efficient way to find if a Matrix is Sub-Matrix of another one?


Given two matrices A and B.

Is there efficient or more pythonic way to find if B is a Sub-Matrix of A?

matrix

The code below is worked but I got a Time limit exceeded when the matrix is so big!

Note: The matrix data structure is represented as an array of strings.

[Input]

A=[
'7283455864',
'6731158619',
'8988242643',
'3830589324',
'2229505813',
'5633845374',
'6473530293',
'7053106601',
'0834282956',
'4607924137']

B=[
'9505',
'3845',
'3530']

[Code]

def gridSearch(G, P):
    # Write your code here
    n=len(G)    # Matrix G row number
    m=len(G[0]) # Matrix G col number

    r=len(P)    # Matrix P row number
    c=len(P[0]) # Matrix P col number

    found='NO'
    for i in range(n-r+1):
        for j in range(m-c+1):
            start_row=i
            end_row=i+r
            start_col=j
            end_col=j+c
            sub=[]
            if G[start_row][start_col]==P[0][0]:
                sub=[x[start_col:end_col] for x in G[start_row:end_row] ]
            if (sub==P):
                found='YES'
                #print(i,j)
                
    return(found) 

[Expected Output]

YES

Solution

  • Rather than search on a letter by letter basis as you seem to be doing with your code, I would utilize the ability to search for strings within another string as follows:

    def gridSearch(G, P):
        g_sze = len(G)
        p_sze = len(P)
        p_ptr = 0
        for g_ptr, g_row in enumerate(G):
            if P[p_ptr] in g_row:
                p_ptr += 1
                if p_ptr == p_sze:
                    return True
            else:
                p_ptr = 0
                if g_sze - g_ptr < p_sze-p_ptr:
                    return False
    
        return False
    

    The above code makes use of two efficiency approaches, first it searches the arrays by rows and secondly it stops searching rows when the ability to match the remaining rows of the smaller array is no longer possible

    Given your second example, here is an approach which uses the string search approach and requires column alignment.

    def gridSearch2(G, P):
        g_sze = len(G)
        p_sze = len(P)
        candidates = []
        # First scan for possible start postions
        for row in range(g_sze - p_sze + 1):
            idx = 0
            while idx < g_sze - p_sze:
                ptr = G[row].find(P[0], idx)
                if ptr < 0:
                    break
                candidates.append((row, ptr+idx))
                idx = idx + ptr + 1
            # test each possible start postion for matching follow on rows
            while len(candidates)  > 0:
            row, idx  = candidates.pop(0);
            rslt = True
            for pr in range(1, p_sze):
                if G[row + pr].find(P[pr], idx) != idx:
                    rslt = False
                    break
            if rslt:
                return True
        return False