You are given an N × N matrix in which every cell is colored black or white. Columns are numbered from 0 to N-1 (from left to right). This coloring is represented by a non-empty array of integers A. If the K-th number in the array is equal to X then the X lowest cells in the K-th column of the matrix are black. The rest of the cells in the K-th column are white. The task is to calculate the side length of the biggest black square (a square containing only black cells).
Write a function:
class Solution { public int solution(int[] A); }
that, given an array of integers A of length N representing the coloring of the matrix, returns the side length of the biggest black square.
Examples:
1. Given A = [1, 2, 5, 3, 1, 3], the function should return 2. For example, the black square of side 2 contains the two lowest rows of the 1st and 2nd columns (counting from 0).
2. Given A = [3, 3, 3, 5, 4], the function should return 3. For example, the biggest black square has side 3 and contains the three lowest rows of the last three columns.
3. Given A = [6, 5, 5, 6, 2, 2], the function should return 4. The biggest black square has side 4 and contains the four lowest rows of the first four columns.
Write an efficient algorithm for the following assumptions:
- N is an integer within the range [1..100,000];
- each element of array A is an integer within the range [1..N].
import java.util.*;
class Solution {
class Square {
int height, width;
Square(int height, int width) {
this.height = height;
this.width = width;
}
}
int M = 1;
void calculateMax(Square a) {
if (a.height > M && a.width > M)
M = Math.min(a.height, a.width);
}
public int solution(int[] A) {
Stack<Square> S = new Stack<Square>();
for (int i = 0; i < A.length; i++) {
int a = A[i];
if (S.isEmpty()) {
S.push(new Square(a, 1));
continue;
}
Square a0 = S.peek();
if (a > a0.height) {
S.push(new Square(a, 1));
continue;
}
if (a == a0.height) {
a0.width++;
calculateMax(a0);
continue;
}
// a<a0.height
a0 = S.pop();
while (!S.isEmpty()) {
Square a1 = S.peek();
// a>a1, a replace a0
if (a > a1.height) {
a0.height = a;
a0.width++;
S.push(a0);
calculateMax(a0);
break;
}
// a==a1
if (a == a1.height) {
a1.width += a0.width + 1;
calculateMax(a1);
break;
}
// a<a1
if (a < a1.height) {
a1.width += a0.width;
calculateMax(a1);
a0 = S.pop();
}
}
if (S.isEmpty()) {
a0.height = a;
a0.width++;
S.push(a0);
calculateMax(a0);
}
}
Square a0 = S.pop();
while (!S.isEmpty()) {
S.peek().width += a0.width;
calculateMax(a0);
a0 = S.pop();
}
return M;
}
}
import java.util.*;
class Solution {
class Square {
int height, width;
Square(int height, int width) {
this.height = height;
this.width = width;
}
}
int M = 1;
void calculateMax(Square a) {
if (a.height > M && a.width > M)
M = Math.min(a.height, a.width);
}
public int solution(int[] A) {
Stack<Square> S = new Stack<Square>();
for (int i = 0; i < A.length; i++) {
int a = A[i];
if (S.isEmpty()) {
S.push(new Square(a, 1));
continue;
}
Square a0 = S.peek();
if (a > a0.height) {
S.push(new Square(a, 1));
continue;
}
if (a == a0.height) {
a0.width++;
calculateMax(a0);
continue;
}
// a<a0.height
a0 = S.pop();
while (!S.isEmpty()) {
Square a1 = S.peek();
// a>a1, a replace a0
if (a > a1.height) {
a0.height = a;
a0.width++;
S.push(a0);
calculateMax(a0);
break;
}
// a==a1
if (a == a1.height) {
a1.width += a0.width + 1;
calculateMax(a1);
break;
}
// a<a1
if (a < a1.height) {
a1.width += a0.width;
calculateMax(a1);
a0 = S.pop();
}
}
if (S.isEmpty()) {
a0.height = a;
a0.width++;
S.push(a0);
calculateMax(a0);
}
}
Square a0 = S.pop();
while (!S.isEmpty()) {
S.peek().width += a0.width;
calculateMax(a0);
a0 = S.pop();
}
return M;
}
}
import java.util.*;
class Solution {
class Square {
int height, width;
Square(int height, int width) {
this.height = height;
this.width = width;
}
}
int M = 1;
void calculateMax(Square a) {
if (a.height > M && a.width > M)
M = Math.min(a.height, a.width);
}
public int solution(int[] A) {
Stack<Square> S = new Stack<Square>();
for (int i = 0; i < A.length; i++) {
int a = A[i];
if (S.isEmpty()) {
S.push(new Square(a, 1));
continue;
}
Square a0 = S.peek();
if (a > a0.height) {
S.push(new Square(a, 1));
continue;
}
if (a == a0.height) {
a0.width++;
calculateMax(a0);
continue;
}
// a<a0.height
a0 = S.pop();
while (!S.isEmpty()) {
Square a1 = S.peek();
// a>a1, a replace a0
if (a > a1.height) {
a0.height = a;
a0.width++;
S.push(a0);
calculateMax(a0);
break;
}
// a==a1
if (a == a1.height) {
a1.width += a0.width + 1;
calculateMax(a1);
break;
}
// a<a1
if (a < a1.height) {
a1.width += a0.width;
calculateMax(a1);
a0 = S.pop();
}
}
if (S.isEmpty()) {
a0.height = a;
a0.width++;
S.push(a0);
calculateMax(a0);
}
}
Square a0 = S.pop();
while (!S.isEmpty()) {
S.peek().width += a0.width;
calculateMax(a0);
a0 = S.pop();
}
return M;
}
}
The solution obtained perfect score.
Tests with the biggest square surrounded by shorter columns. N <= 10.
Tests with alternating small and big numbers (relatively). N <= 15.
Two monotonic sequences or one monotonic and one constant. N <= 75.
Tests with local maximums and local minimums. N <= 75.