Shellhead96's blog

By Shellhead96, history, 7 years ago, In English

Given a matrix of ‘O’ and ‘X’, find the largest subsquare surrounded by ‘X’? Can there be a better solution than O(n^3) ??

  • Vote: I like it
  • -5
  • Vote: I do not like it

| Write comment?
»
7 years ago, # |
Rev. 3   Vote: I like it 0 Vote: I do not like it

Run DFS from corner cell. DFS can traverse in 8 directions. We can only traverse cells that are not marked with 'X'. Now, every time we visit a cell, we mark it as bad.

After the above step, only the cells that are marked with X or surrounded by 'X' characters will not be marked as 'bad'. We can then mark each of the non 'X' non-bad cells with a unique number, say 0.

Now our problem is reduced to finding the largest rectangle that contains only zeros.

This problem is solvable in O(n^3) using kadane algorithm to find the maximum sum rectangle in a 2-d grid. But since you were looking for a solution that is better than O(n^3), let's look at a better solution.

Assuming that the unique number that we used earlier is 0, we perform a horizontal sum of contiguous sequences of 0 in the grid. E.g.

0 0
0 0

becomes

1 1
2 2

Now, we can use the maximum area in a histogram subroutine to find the largest rectangle with only 0 inside. This solution works in O(n^2).

  • »
    »
    7 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    As i understand, your solution finds the largest rectangle isolated by 'X', but not surrounded (sry for my English). Author wrote about this problem. I think it'll be clearer with picture:

    And yes, we need to find the largest subsquare.

»
7 years ago, # |
  Vote: I like it 0 Vote: I do not like it

As I can understand O(N3) solution — you fix top-left corner of square, iterate over length of square, check in O(1) with prefix-sums if such square exists.

What we can observe that top-left and bottom-right corners of square lie on one main diagonal (x - y = const).

Let's calculate for each cell (x, y) next value:

value[x, y] = x + min(down[x, y], right[x, y]),

where down[x, y] — maximal length of vertical 'X' subsegment, started from (x, y) down,
right[x, y] — the same for horizontal subsegment, started right.

So let's process each main diagonal x - y = d separately.

For each vertex (x, x - d) we can calculate minX — the leftmost possible x of subsquare with (x, x - d) as bottom-right corner of it (can be done in O(1) with left[x, x - d] and up[x, x - d]).

We can make query "the minimal x0 that minX ≤ x0 ≤ x with value[x0, x0 - d] ≥ x" and try to update answer with square (x0, x0 - d)(x, x - d)

This query can be done in O(logN) next way.

Construct segment tree, that can handle two queries:

  1. set(index, value), where value is 0 or 1.
  2. getLeftmostOne(left, right) — returns index of leftmost 1 at the segment (or -1, if segment contains only 0s).

There is algorithm of processing:

  • At the start call set(x, 1) for each x.
  • Create array of vectors where vector[x] contains all x0 such that value[x0, x0 - d] = x.
  • Process all vertices in increasing order of x, after processing x = c for each x0 in vector[c] call set(x0, 0).
  • Now our query can be done as 'get index of the leftmost 1 at the segment (minX, x)'.
  • »
    »
    7 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    Maybe I misread problem.

    I wrote solution for problem "find the largest subsquare that can contains 'X' and 'O' inside, but only 'X' on it's sides".

    If we need to solve problem "find the largest subsquare that can contains only 'O' inside, but 'X' on it's sides" — we can do it simplier with the same complexity O(n2 * logn).

    • Make binary search from minX to x and find maximal subsquare, that contains only 'O' inside.
    • We can store 'O' as 0 and 'X' as 1, so check in BS can be done with 2D-prefix sums in O(1) — square contains only 'O' if sum equals to 0.
    • After we found x0 we need to check that x0 + value[x0, x0 - d] ≥ x.
    • »
      »
      »
      7 years ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      For this version of problem there is O(n^2) solution. It is an optimization of naive algorithm.

      Naive approach
      Optimization

      Used the same logic as here.

      • »
        »
        »
        »
        7 years ago, # ^ |
          Vote: I like it 0 Vote: I do not like it

        Oh, yes, thx, I forgot about this optimization.

»
7 years ago, # |
Rev. 2   Vote: I like it +8 Vote: I do not like it

Let's fix top-left corner of the square. We need to find the largest square with this corner. We can use binary search and check whether the square is filled, using prefix sums.

EDIT: sorry, misread