|
| 1 | +# [Problem 756: Pyramid Transition Matrix](https://leetcode.com/problems/pyramid-transition-matrix/description/?envType=daily-question) |
| 2 | + |
| 3 | +## Initial thoughts (stream-of-consciousness) |
| 4 | +We need to build a pyramid from a given bottom string up to a single top letter. Each adjacent pair in a row determines (via allowed patterns) what letters can appear above them. That suggests a backtracking / DFS search: given the current row, enumerate all possible rows above it (consistent with allowed patterns), and recursively try to build further until length 1. To make enumeration fast, precompute a mapping from bottom-pair (two letters) to the list of allowed top letters. Since choices multiply, memoization of failed bottoms (or successful ones) will prune repeated work. The bottom length is at most 6, so depth is small (<=5), but branching could be up to 6 per pair (since alphabet size is {A..F}), so worst-case states are manageable with pruning. |
| 5 | + |
| 6 | +## Refining the problem, round 2 thoughts |
| 7 | +- Build a dict: key = pair of chars (string of length 2), value = list (or set) of top letters allowed. |
| 8 | +- DFS function that takes a current row (string). If length == 1, return True. |
| 9 | +- To form the next row, for each adjacent pair in current row, get candidate tops; if any pair has no candidates, this branch is impossible. |
| 10 | +- Use a helper to generate all possible next-row strings via backtracking on positions (cartesian product of candidate lists) and for each complete candidate next-row, recurse. |
| 11 | +- Memoize bottoms that are proven impossible to reach the top (store them in a set) to avoid re-exploring identical states. |
| 12 | +- Edge cases: allowed may be empty -> immediately false unless bottom length == 1 (but constraints say bottom length >=2). Also allowed strings are unique, so no duplicates to worry about. |
| 13 | +- Time complexity: worst-case branching roughly O(k^(n)) where n is bottom length, k <= 6 (alphabet size). But with memoization and small n (<=6), it's fine. Space: recursion depth <= 6 and memo stores strings up to length 6. |
| 14 | + |
| 15 | +## Attempted solution(s) |
| 16 | +```python |
| 17 | +from typing import List, Dict, Set |
| 18 | + |
| 19 | +class Solution: |
| 20 | + def pyramidTransition(self, bottom: str, allowed: List[str]) -> bool: |
| 21 | + # Build mapping from pair -> list of possible tops |
| 22 | + mp: Dict[str, List[str]] = {} |
| 23 | + for s in allowed: |
| 24 | + pair = s[:2] |
| 25 | + top = s[2] |
| 26 | + if pair not in mp: |
| 27 | + mp[pair] = [] |
| 28 | + mp[pair].append(top) |
| 29 | + |
| 30 | + # Memoization for bottoms that cannot reach the top |
| 31 | + failed: Set[str] = set() |
| 32 | + |
| 33 | + def dfs(curr: str) -> bool: |
| 34 | + # If we've reached the top |
| 35 | + if len(curr) == 1: |
| 36 | + return True |
| 37 | + if curr in failed: |
| 38 | + return False |
| 39 | + |
| 40 | + # For each adjacent pair, fetch candidate tops |
| 41 | + # If any pair has no candidates, this bottom is impossible |
| 42 | + n = len(curr) |
| 43 | + candidates = [] |
| 44 | + for i in range(n - 1): |
| 45 | + pair = curr[i:i+2] |
| 46 | + if pair not in mp: |
| 47 | + failed.add(curr) |
| 48 | + return False |
| 49 | + candidates.append(mp[pair]) |
| 50 | + |
| 51 | + # Backtracking to build next row from candidates lists |
| 52 | + next_row_chars = [] |
| 53 | + |
| 54 | + def build_next(pos: int) -> bool: |
| 55 | + if pos == len(candidates): |
| 56 | + next_row = ''.join(next_row_chars) |
| 57 | + if dfs(next_row): |
| 58 | + return True |
| 59 | + return False |
| 60 | + for ch in candidates[pos]: |
| 61 | + next_row_chars.append(ch) |
| 62 | + if build_next(pos + 1): |
| 63 | + return True |
| 64 | + next_row_chars.pop() |
| 65 | + return False |
| 66 | + |
| 67 | + # If no possible construction leads to the top, memoize and return False |
| 68 | + if not build_next(0): |
| 69 | + failed.add(curr) |
| 70 | + return False |
| 71 | + return True |
| 72 | + |
| 73 | + return dfs(bottom) |
| 74 | +``` |
| 75 | +- Notes: |
| 76 | + - Approach: recursive DFS with backtracking to construct all possible next rows, using a map from pairs to allowed top letters and a memo set to prune failing bottoms. |
| 77 | + - Time complexity: worst-case exponential in bottom length (rough upper bound O(k^(n)) where k <= 6 and n = len(bottom)), but n <= 6 and memoization prunes repeated states. Practically efficient under given constraints. |
| 78 | + - Space complexity: recursion depth O(n), plus memo storing failed bottoms (each <= length 6). |
0 commit comments