Leetcode 756. Pyramid Transition Matrix
The problem is known as “756. Pyramid Transition Matrix” on LeetCode.
We are given a bottom
string and a list of transition rules in the format “XYZ” where “XY” is the base and “Z” is the resulting character. Our task is to determine if we can build a pyramid to the top using these rules.
Example:
bottom = "BCD"
allowed = ["BCG", "CDE", "GEA", "FFF"]
The rules mean:
We need to determine if we can build a pyramid where bottom
is the base and we can place characters on top according to the allowed transition rules.
bottom
and allowed
are uppercase letters?
bottom
and the number of transitions in allowed
?
bottom.length()
can be up to 8.allowed.length()
can be up to 200.true
if we can build the pyramid to the top using the given transitions, otherwise, return false
.We can use a Depth First Search (DFS) approach with memoization to solve this problem. We will start from the bottom
and recursively try to construct the top of the pyramid using the allowed transitions. Memoization will help avoid recalculating the same subproblems.
allowed
transitions into a more accessible structure, such as a dictionary.Here is a possible implementation of the solution in C++:
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include <functional>
using namespace std;
class Solution {
public:
bool pyramidTransition(string bottom, vector<string>& allowed) {
// Build the dictionary for transitions
unordered_map<string, unordered_set<char>> transitions;
for (const string& triplet : allowed) {
transitions[triplet.substr(0, 2)].insert(triplet[2]);
}
// Memoization map: Cache previously computed results
unordered_map<string, bool> memo;
// Function for recursion and DFS
function<bool(string)> dfs = [&](string bottom) {
// If the bottom is of length 1, we reached the top
if (bottom.size() == 1) return true;
// If we have seen this bottom before return the cached result
if (memo.find(bottom) != memo.end()) return memo[bottom];
// Trying to build the next level
for (int i = 0, n = bottom.size(); i < n - 1; ++i) {
string base = bottom.substr(i, 2);
if (transitions.find(base) == transitions.end()) return memo[bottom] = false;
}
// To store all combinations of possible next levels
vector<string> nextLevelCandidates;
generateNextLevel(bottom, "", 0, nextLevelCandidates, transitions);
for (const string& nextLevel : nextLevelCandidates) {
if (dfs(nextLevel)) return memo[bottom] = true;
}
return memo[bottom] = false;
};
return dfs(bottom);
}
private:
void generateNextLevel(const string& bottom, const string& current, int pos, vector<string>& nextLevelCandidates,
const unordered_map<string, unordered_set<char>>& transitions) {
if (pos == bottom.size() - 1) {
nextLevelCandidates.push_back(current);
return;
}
string base = bottom.substr(pos, 2);
const auto& possibleChars = transitions.at(base);
for (char ch : possibleChars) {
generateNextLevel(bottom, current + ch, pos + 1, nextLevelCandidates, transitions);
}
}
};
The time complexity of this solution is difficult to bound tightly, but it can be exponential in the worst case due to the combination of states. Practical performance will depend on the branching factor of each level and the effectiveness of memoization in pruning the search space.
Got blindsided by a question you didn’t expect?
Spend too much time studying?
Or simply don’t have the time to go over all 3000 questions?