756. Pyramid transformation matrix

ID: 756
TITLE: Pyramid transformation matrix
TAG: Java,Python

Method 1: state transition

Algorithm:

Let's simulate the state that a block can be in. Each state is a binary number, set bit k if a block of type k is possible. Then, we create a transformation map t [state1] [State2] - > state. It takes the left and right States and outputs all possible parent states.

Finally, applying these transformations is very simple. However, this approach is not correct because the transformation is not independent. For example, if we are on line A, {B or C}, A, and the tuple in allowed is (A, B, D), (C, A, D). So no matter we choose {B or C}, we can't create the next line of the pyramid.

class Solution(object):
    def pyramidTransition(self, bottom, allowed):
        T = [[0] * (1 << 7) for _ in xrange(1 << 7)]
        for triple in allowed:
            u, v, w = (1 << (ord(x) - ord('A')) for x in triple)
            for b1 in xrange(1 << 7):
                if u & b1:
                    for b2 in xrange(1 << 7):
                        if v & b2:
                            T[b1][b2] |= w

        state = [1 << (ord(x) - ord('A')) for x in bottom]
        while len(state) > 1:
            for i in xrange(len(state) - 1):
                state[i] = T[state[i]][state[i+1]]
            state.pop()
        return bool(state[0])
class Solution {
    public boolean pyramidTransition(String bottom, List<String> allowed) {
        int[][] T = new int[1 << 7][1 << 7];
        for (String triple: allowed) {
            int u = 1 << (triple.charAt(0) - 'A');
            int v = 1 << (triple.charAt(1) - 'A');
            int w = 1 << (triple.charAt(2) - 'A');
            for (int b1 = 0; b1 < (1 << 7); ++b1) if ((u & b1) > 0)
                for (int b2 = 0; b2 < (1 << 7); ++b2) if ((v & b2) > 0)
                    T[b1][b2] |= w;
        }

        int[] state = new int[bottom.length()];
        int t = 0;
        for (char c: bottom.toCharArray())
            state[t++] = 1 << (c - 'A');
        while (t-- > 1)
            for (int i = 0; i < t; ++i)
                state[i] = T[state[i]][state[i+1]];
        return state[0] > 0;
    }
}

Complexity analysis

  • Time complexity: O(22AA+N2)O(2^{2\mathcal{A}}A + N^2)O(22AA+N2). Where NNN refers to the length of bottom, AAA refers to the length of allowed, and A\mathcal{A}A refers to the size of letters.
  • Spatial complexity: O(22A)O(2^{2\mathcal{A}})O(22A).

Method 2: depth first search

We try every combination of squares in detail.

Algorithm:

We need to create a transformation map T from the list of triples. This mapping T[x][y] = {set of z} will be all possible parent blocks of left child X and right child y.

Then, in order to solve the next row, we generate all possible combinations of the next row and solve them. Returns True if any one of these combinations is solvable, and False otherwise.

class Solution(object):
    def pyramidTransition(self, bottom, allowed):
        T = collections.defaultdict(set)
        for u, v, w in allowed:
            T[u, v].add(w)

        #Comments can be used to cache intermediate results
        #seen = set()
        def solve(A):
            if len(A) == 1: return True
            #if A in seen: return False
            #seen.add(A)
            return any(solve(cand) for cand in build(A, []))

        def build(A, ans, i = 0):
            if i + 1 == len(A):
                yield "".join(ans)
            else:
                for w in T[A[i], A[i+1]]:
                    ans.append(w)
                    for result in build(A, ans, i+1):
                        yield result
                    ans.pop()

        return solve(bottom)
class Solution {
    int[][] T;
    Set<Long> seen;

    public boolean pyramidTransition(String bottom, List<String> allowed) {
        T = new int[7][7];
        for (String a: allowed)
            T[a.charAt(0) - 'A'][a.charAt(1) - 'A'] |= 1 << (a.charAt(2) - 'A');

        seen = new HashSet();
        int N = bottom.length();
        int[][] A = new int[N][N];
        int t = 0;
        for (char c: bottom.toCharArray())
            A[N-1][t++] = c - 'A';
        return solve(A, 0, N-1, 0);
    }

    //A[i] - the ith row of the pyramid
    //R - integer representing the current row of the pyramid
    //N - length of current row we are calculating
    //i - index of how far in the current row we are calculating
    //Returns true iff pyramid can be built
    public boolean solve(int[][] A, long R, int N, int i) {
        if (N == 1 && i == 1) { // If successfully placed entire pyramid
            return true;
        } else if (i == N) {
            if (seen.contains(R)) return false; // If we've already tried this row, give up
            seen.add(R); // Add row to cache
            return solve(A, 0, N-1, 0); // Calculate next row
        } else {
            // w's jth bit is true iff block #j could be
            // a parent of A[N][i] and A[N][i+1]
            int w = T[A[N][i]][A[N][i+1]];
            // for each set bit in w...
            for (int b = 0; b < 7; ++b) if (((w >> b) & 1) != 0) {
                A[N-1][i] = b; //set parent to be equal to block #b
                //If rest of pyramid can be built, return true
                //R represents current row, now with ith bit set to b+1
                // in base 8.
                if (solve(A, R * 8 + (b+1), N, i+1)) return true;
            }
            return false;
        }
    }
}

Complexity analysis

  • Time complexity: O(AN)O(\mathcal{A}^{N})O(AN), where NNN refers to the length of bottom, and A\mathcal{A}A refers to the size of letters.
  • Spatial complexity: O (N2) O (N2) O (N2).
136 original articles published, 175 praised, 20000 visited+
Private letter follow

Tags: Java Python REST

Posted on Fri, 14 Feb 2020 10:56:27 -0500 by Xeon