Предварительный комментарий: «Расстояние Левенштейна» - это расстояние редактирования (согласно общему определению). Это очень распространенная проблема; Вам, вероятно, даже не нужно беспокоиться о написании решения самостоятельно. Ищите существующий код.
Теперь, наконец, для правильного ответа ... На самом деле вам вообще не нужна матрица, и вам, конечно, не нужно ее "сохранять": достаточно просто держать "переднюю часть" своего матрица динамического программирования, а не целое.
Но какой «фронт» вы выберете и как его продвигать? Я предлагаю вам использовать антидиагонали в качестве фронта, и, учитывая каждую антидиагональность, одновременно вычислять следующую антидиагональность. Таким образом, это будет {(0,0)}, затем {(0,1), (1,0)}, затем {(0,2), (1,1), (2,0)} и т. Д. на. Каждая антидиагональ требует не более двух более ранних антидиагоналей - и если мы будем хранить значения каждой антидиагонали последовательно в памяти, то схема доступа, идущая вверх по следующей антидиагональности, представляет собой линейную прогрессию вдоль предыдущих антидиагоналей - что отлично подходит для кеша (см. мой другой ответ ).
Таким образом, вы будете "согласовывать" вычисления, предоставляя каждому потоку кучу последовательных антидиагональных элементов для вычисления; Это должно делать свое дело. И в любой момент вы сохраните только 3 антидиагональных в памяти: тот, над которым вы работаете, и два предыдущих. Вы можете переключаться между тремя такими буферами, чтобы не перераспределять память все время (но затем убедитесь, что предварительно выделяете буферы с максимальной антидиагональной длиной).
Все это должно работать в основном одинаково для неквадратного случая.