connected-componentsapldyalog

How can I label connected components in APL?


I'm trying to do leet puzzle https://leetcode.com/problems/max-area-of-island/, requiring labelling connected (by sides, not corners) components.

How can I transform something like

0 0 1 0 0
0 0 0 0 0
0 1 1 0 1
0 1 0 0 1
0 1 0 0 1

into

0 0 1 0 0
0 0 0 0 0
0 2 2 0 3
0 2 0 0 3
0 2 0 0 3

I've played with the stencil operator and also tried using scan operators but still not quite there. Can somebody help?


Solution

  • We can start off by enumerating the ones. We do the by applying the function (where, but since all are 1s, it is equivalent to 1,2,3,…) @ at the subset masked by the bits themselves, i.e. ⍸@⊢:

          ⍸@⊢m
    0 0 1 0 0
    0 0 0 0 0
    0 2 3 0 4
    0 5 0 0 6
    0 7 0 0 8
    

    Now we need to flood-fill the lowest number in each component. We do this with repeated application until the fix-point ⍣≡ of processing Moore neighbourhoods ⌺3 3. To get the von Neumann neighbours, we reshape the 9 elements in the Moore neighbourhood into a 4-row 2-column matrix with 4 2⍴ and use ⊢/ to select the right column. We remove any 0s with 0~⍨ them prepend , the original value ⍵[2;2] (even if 0) and have ⌊/ select the smallest value:

            {⌊/⍵[2;2],0~⍨⊢/4 2⍴⍵}⌺3 3⍣≡⍸@⊢m
    0 0 1 0 0
    0 0 0 0 0
    0 2 2 0 4
    0 2 0 0 4
    0 2 0 0 4
    

    We map the values to indices by finding their indices ⍳⍨ in the unique elements of ∘∪ 0 followed by , the ravelled matrix ,:

            (⊢⍳⍨∘∪0,,){⌊/⍵[2;2],0~⍨⊢/4 2⍴⍵}⌺3 3⍣≡⍸@⊢m
    1 1 2 1 1
    1 1 1 1 1
    1 3 3 1 4
    1 3 1 1 4
    1 3 1 1 4
    

    And decrement which adjusts back to begin with zero:

            ¯1+(⊢⍳⍨∘∪0,,){⌊/⍵[2;2],0~⍨⊢/4 2⍴⍵}⌺3 3⍣≡⍸@⊢m
    0 0 1 0 0
    0 0 0 0 0
    0 2 2 0 3
    0 2 0 0 3
    0 2 0 0 3