Найти, существует ли малая матрица в большой матрице в O (n) - PullRequest
0 голосов
/ 23 марта 2020

Мне задали вопрос в интервью:
Учитывая матрицу A и матрицу B, я должен написать программу, чтобы выяснить, существует ли матрица B в матрице A.

Проблема в том, что у меня есть сделать это O (n) раз.

Это единственный подход, который я придумал:

public class Matrix {

    public static void main (String [] args) 
    {
        boolean flag = false;
        int a[][] = {   {1,2,3,4},
                        {5,6,7,8},
                        {9,10,11,12},
                        {13,14,15,16} };

        int b[][] = {   {11,12},
                        {15,16} };


        for (int i=0;i<a.length-b.length+1;i++)
        {
            for(int j=0;j<a[0].length-b[0].length+1;j++)
            {
                if(a[i][j]==b[0][0])
                {
                    flag = true;

                    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])
                            {
                                flag = false;
                                break;
                            }
                        }
                    }

                    if(flag)
                    {
                        System.out.println("i= " + i + " j= " + j);
                        return;
                    }


                }
            }
        }


    }
}

Я не знаю, как преобразовать его в O (n).

Есть ли метод для поиска, если маленькая матрица B существует в большой матрице A в O (n)?

Ответы [ 2 ]

0 голосов
/ 23 марта 2020

( EDITED )

Предположим, у вас есть матрица A размера n x m и матрица B размеров k x l, проблема поиска вхождений B в A имеет простую сложную временную сложность O(n m k l) с требованием O(1) памяти.

В общем, вы можете легко доказать, что вы не можете быть лучше, чем O(n m), рассматривая случай k = l = 1, который требует проверки всех элементов содержащей матрицы, поэтому O(n m). Это та же самая причина, по которой алгоритмы строки поиска не могут быть (глобально) суперлинейными.


Я предполагаю, что ваше требование быть O(N) более точно соответствует требованию быть O(n m). Если бы это было возможно, вы могли бы предположить, что подобный алгоритм может быть адаптирован к задаче поиска строки со сложностью O(n) (n - размер ввода), независимо от размера шаблона k. Такой алгоритм не был найден (и, вероятно, даже существует). По этой причине я склонен полагать, что то, что вы ищете, в настоящее время, по возможности, находится за пределами человеческого знания.


Вместо этого, на основе алгоритмов поиска строк литературы то, к чему вы могли бы стремиться, - это достичь сложности O(n m + k l).

Возможным подходом было бы адаптировать один из вышеупомянутых алгоритмов поиска строки к этой проблеме, и, следовательно, вы должны быть в состоянии получить аналогичные временные сложности и требования к памяти.

Например, ваш алгоритм и @ PaulHankin answer являются описанием адаптации алгоритма Рабина-Карпа к 2D корпусу. В то время как ваша версия использует действительно плохой ха sh (первый элемент каждой матрицы), если бы вы рассчитывали более сложный / подходящий га sh (как предложено, но не предоставлено - по крайней мере, на момент написания статьи) в @ PaulHankin ответ ), как скользящий га sh, тогда вы сможете пропустить две самые внутренние петли большую часть времени, в то время как вращающийся ха sh будет убедитесь, что вы не добавляете в алгоритм дополнительную сложность, зависящую от размера ввода, что приведет к O(n m + k l) сложности времени (O(k l) получается из вычисления ha sh на B) и O(1) памяти требование.

Адаптация других алгоритмов поиска строк (например, алгоритм Кнута-Морриса-Пратта (KMP) или Двусторонний алгоритм поиска строк (2WSS) ) может потребоваться некоторая «линеаризация» алгоритма (а не только постановка задачи), что будет означать использование модуля arithmeti c для определения правильных смещений при любых обстоятельствах, что может быть утомительным, но я не вижу причины, по которой это было бы невозможно или привело бы к потере ожидаемых сложностей.

Другой вариант - адаптировать алгоритмы поиска строк для работы с чередованием в каждом измерении. Но опять же, это может оказаться таким же сложным, как и работа с какой-то «линеаризованной» проблемой.

Последнее сообщение здесь заключается в том, что определенно возможно go выйти за пределы O(n m k l) и в конечном итоге O(n m + k l), но это не так. легко.

0 голосов
/ 23 марта 2020

Вы можете использовать 2D прокатку га sh.

Учитывая (большую) входную матрицу A[N][N] и меньшую входную матрицу M[K][K], создайте новую матрицу H1[N][N-K+1], хэшируя каждую K последовательных элементов в каждом ряду, например, так:

 H1[i][j] = hash(A[i][j], A[i][j+1], ..., A[i][j+K-1])

Если ваша функция ha sh выбрана в качестве скользящей функции ha sh (посмотрите вверх), она выполняется за линейное время, потому что Вы можете построить H1[i][j+1] из H1[i][j] за O (1) раз.

Далее, га sh вверх по столбцам, построив новую матрицу H2[N-K+1][N-K+1]:

 H2[i][j] = hash(H1[i][j], H1[i+1][j], ..., A[i+K-1][j])

Примените ту же процедуру к вашей меньшей матрице (которая создает матрицу с одним элементом).

Теперь сравните одиночное значение ha sh из меньшей матрицы с каждым элементом H2, и если они равны, у вас почти наверняка есть совпадение (вы можете проверить поэлементно).

...