Gọi \(L(i, j)\) là số số 1 (hoặc số số 0) liên tiếp trên dòng \(i\), kết thúc ở ô \(A(i, j)\).
(Theo chiều từ trái sang phải).
Gọi \(C(i, j)\) là số số 1 (hoặc số số 0) liên tiếp trên cột \(j\), kết thúc ở ô \(A(i, j)\).
(Theo chiều từ trên xuống dưới).
Gọi \(F(i, j)\) là độ dài cạnh hình vuông lớn nhất có góc phải dưới ở \(A(i, j)\).
Kết quả bài toán là max của mảng F.
Ta tính \(F(i, j)\) từ \(F(i-1, j-1)\), \(L(i, j)\) và \(C(i, j)\) như sau:
\[F(i, j) = \begin{cases}
\mathrm{min}(L(i, j), C(i, j), 1 + F(i-1, j-1)) & \quad \text{if } A(i, j) = A(i-1, j-1) \\
1 & \quad \text{otherwise}
\end{cases}\]
Tính \(L(i, j)\) từ \(L(i, j-1)\) như sau:
\[L(i, j) = \begin{cases}
L(i, j-1) + 1 & \quad \text{if } A(i, j) = A(i, j-1) \\
1 & \quad \text{otherwise}
\end{cases}\]
Tương tự, ta tính \(C(i, j)\) từ \(C(i-1, j)\).
Nhận thấy chỉ cần dùng 2 dòng cuối cùng của các mảng \(A, L, C, F\) để tính,
có thể giảm độ phức tạp bộ nhớ về \(O(n)\). Xem code optimized.cpp
để xem cải tiến này.