Ejemplo n.º 1
0
def flip_inside_O_by_UF(board: List[List[str]]) -> None:
    if not board:
        board = []
        return

    uf = UnionFind(board)
    dummyIdx = uf.r * uf.c

    for i in range(uf.r):
        for j in range(uf.c):
            if board[i][j] == 'O':
                ijIdx = i * uf.c + j
                # connect all boundary nodes to the ONE dummy node
                if i in (0, uf.r - 1) or j in (0, uf.c - 1):
                    uf.union(ijIdx, dummyIdx)
                # check its right neighbor is connected ?
                if j + 1 < uf.c and board[i][j + 1] == 'O':
                    uf.union(ijIdx, ijIdx + 1)
                # check its down neighbor is connected ?
                if i + 1 < uf.r and board[i + 1][j] == 'O':
                    uf.union(ijIdx, ijIdx + uf.c)

    for i in range(uf.r):
        for j in range(uf.c):
            if uf.find_root(i * uf.c + j) != uf.find_root(uf.dummyIdx):
                board[i][j] = 'X'
Ejemplo n.º 2
0
def num_similiar_groups_using_union_find(A: List[str]) -> int:
    def is_similiar(w1, w2):
        cnt = 0
        for i1, i2 in zip(w1, w2):
            cnt += (i1 != i2)
            if cnt > 2:
                return False
        return cnt == 2

    uf = UnionFind(A)

    strlen, wordlen = len(A[0]), len(A)
    if wordlen < strlen * strlen:
        for i, w1 in enumerate(A[:-1]):
            for w2 in A[i + 1:]:
                if is_similiar(w1, w2):
                    uf.union(w1, w2)
    else:
        given_words = set(A)
        for w in given_words:
            for i in range(strlen):
                for j in range(i + 1, strlen):
                    new = w[:i] + w[j] + w[i + 1:j] + w[i] + w[j + 1:]
                    if new in given_words:
                        uf.union(w, new)

    return len({uf.find_root(w) for w in uf.p})
Ejemplo n.º 3
0
def rm_stones_using_union_find(stones: List[List[int]]) -> int:
    if not stones:
        return 0

    uf = UnionFind()
    for x, y in stones:
        for i, j in stones:
            if x == i or y == j:
                uf.union(10000 * x + y, 10000 * i + j)

    return len(uf.p) - len({uf.find_root(10000 * x + y) for x, y in stones})
Ejemplo n.º 4
0
def min_malware_spread_using_union_find(graph: List[List[int]],
                                        initial: List[int]) -> int:
    N = len(graph)
    uf = UnionFind(N)
    for i in range(N):
        for j in range(i):
            if graph[i][j]:
                uf.union(i, j)

    a_roots_count = collections.Counter([uf.find_root(i) for i in uf.p])
    v_roots_count = collections.Counter([uf.find_root(v) for v in initial])

    cnt, idx = 0, min(initial)
    for vid in initial:
        v_root = uf.find_root(vid)
        if v_roots_count[v_root] == 1:
            if a_roots_count[v_root] > cnt:
                cnt, idx = a_roots_count[v_root], vid
            elif a_roots_count[v_root] == cnt:
                idx = min(idx, vid)
    return idx
Ejemplo n.º 5
0
def min_malware_spread_II_using_unionfind(graph: List[List[int]],
                                          initial: List[int]) -> int:
    N = len(graph)
    clean = set(list(range(N))) - set(initial)

    uf = UnionFind(N)

    for i in clean:
        for j in clean:
            if graph[i][j]:
                uf.union(i, j)

    # global view from virus
    #  one virus can impact which groups: id by root of a group
    impact_clean_nodes = collections.defaultdict(set)
    for v in initial:
        for i in clean:
            if graph[v][i]:
                impact_clean_nodes[v].add(uf.find_root(i))

    # global view from clean node
    #  one clean node can be impacted by how many virus
    impact_clean_counts = collections.Counter()
    for v in initial:
        for i in impact_clean_nodes[v]:
            impact_clean_counts[i] += 1

    max_impact_num = -1
    ans = min(initial)
    # loop with each virus to see
    #   how many groups it can independently impact
    for v, some_clean_nodes in impact_clean_nodes.items():
        cnt = 0
        for i in some_clean_nodes:
            if impact_clean_counts[i] == 1:
                cnt += uf.sz[i]

        if cnt > max_impact_num or (cnt == max_impact_num and v < ans):
            max_impact_num = cnt
            ans = v

    return ans
Ejemplo n.º 6
0
def regions_by_slashes_using_union_find(grid: List[str]) -> int:
    if not grid:
        return 0

    uf = UnionFind(grid)
    N = len(grid)

    for i, row in enumerate(grid):
        for j, slash in enumerate(row):
            ijIdx = 4 * (i * N + j)
            #    1
            # 0     3
            #    2
            if slash == '/':
                uf.union(ijIdx + 0, ijIdx + 1)
                uf.union(ijIdx + 2, ijIdx + 3)
            elif slash == '\\':
                uf.union(ijIdx + 0, ijIdx + 2)
                uf.union(ijIdx + 1, ijIdx + 3)
            else:
                uf.union(ijIdx, ijIdx + 1)
                uf.union(ijIdx, ijIdx + 2)
                uf.union(ijIdx, ijIdx + 3)

            # union down 1/4 cell except last row N - 1
            if i < N - 1:
                uf.union(ijIdx + 2, ijIdx + 4 * N + 1)

            # union up 1/4 cell except first row 0
            if i >= 1:
                uf.union(ijIdx + 1, ijIdx - 4 * N + 2)

            # union right 1/4 cell except first column N - 1
            if j < N - 1:
                uf.union(ijIdx + 3, ijIdx + 4)

            # union left 1/4 cell except last column 0
            if j >= 1:
                uf.union(ijIdx + 0, ijIdx - 1)

    return sum(uf.find_root(i) == i for i in range(4 * N * N))
Ejemplo n.º 7
0
def calc_equation_by_union_find(equations: List[List[str]],
                                values: List[float],
                                queries: List[List[str]]) -> List[float]:

    uf = UnionFind(equations)
    for i, e in enumerate(equations):
        numer, deno = e
        factor = values[i]
        uf.union(numer, deno, factor)

    ans = []
    for x, y in queries:
        xRoot = uf.find_root(x)
        yRoot = uf.find_root(y)
        # new variable not exist in equations, result must -1.0
        if None in (xRoot, yRoot):
            ans.append(-1.0)
        else:
            if xRoot != yRoot:
                ans.append(-1.0)
            else:
                ans.append(uf.factor[x] / uf.factor[y])

    return ans
Ejemplo n.º 8
0
def rm_stones_using_union_find_simple_view(stones):
    uf = UnionFind()
    for x, y in stones:
        uf.union(x, 10000 + y)

    return len(stones) - len({uf.find_root(i) for i, _ in stones})