We are stacking blocks to form a pyramid. Each block has a color which is a one letter string, like `'Z'`.

For every block of color `C` we place not in the bottom row, we are placing it on top of a left block of color `A` and right block of color `B`. We are allowed to place the block there only if `(A, B, C)` is an allowed triple.

We start with a bottom row of bottom, represented as a single string. We also start with a list of allowed triples allowed. Each allowed triple is represented as a string of length 3.

Return true if we can build the pyramid all the way to the top, otherwise false.

Example 1:

Input: bottom = "XYZ", allowed = ["XYD", "YZE", "DEA", "FFF"]
Output: true
Explanation:
We can stack the pyramid like this:
A
/ \
D E
/ \ / \
X Y Z This works because ('X', 'Y', 'D'), ('Y', 'Z', 'E'), and ('D', 'E', 'A') are allowed triples.

Example 2:

Input: bottom = "XXYX", allowed = ["XXX", "XXY", "XYX", "XYY", "YXZ"]
Output: false
Explanation:
We can't stack the pyramid to the top.
Note that there could be allowed triples (A, B, C) and (A, B, D) with C != D.

Note:

  1. bottom will be a string with length in range [2, 8].
  2. allowed will have length in range [0, 200].
  3. Letters in all strings will be chosen from the set {'A', 'B', 'C', 'D', 'E', 'F', 'G'}.

这道题让我们累一个金字塔,用字母来代表每块砖的颜色,给了一个allowed数组,里面都是长度为三的字符串,比如“ABC”表示C可以放在A和B的上方,注意AB上面也可以放其他的,比如“ABD”也可以同时出现,不过搭积木的时候只能选择一种。给了我们一个bottom字符串,是金字塔的底层,问我们能不能搭出一个完整的金字塔。那么实际上我们就是从底层开始,一层一层的向上来累加,直到搭出整个金字塔。我们先来看递归的解法,首先由于我们想快速知道两个字母上方可以放的字母,需要建立基座字符串和上方字符集合之间的映射,由于上方字符可以不唯一,所以用个HashSet来放字符。我们的递归函数有三个参数,当前层字符串cur,上层字符串above,还有我们的HashMap。如果cur的大小为2,above的大小为1,那么说明当前已经达到金字塔的顶端了,已经搭出来了,直接返回true。否则看,如果上一层的长度比当前层的长度正好小一个,说明上一层也搭好了,我们现在去搭上上层,于是调用递归函数,将above当作当前层,空字符串为上一层,将调用的递归函数结果直接返回。否则表示我们还需要继续去搭above层,我们先算出above层的长度pos,然后从当前层的pos位置开始取两个字符,就是above层接下来需要搭的字符的基座字符,举个例子如下:

  D
/ \ / \
A B C

我们看到现在above层只有一个D,那么pos为1,在cur层1位置开始取两个字符,得到"BC",即是D的下一个位置的字符的基座字符串base。取出了base后,如果HashMap中有映射,则我们遍历其映射的字符集合中的所有字符,对每个字符都调用递归函数,此时above字符串需要加上这个遍历到的字符,因为我们在尝试填充这个位置,如果有返回true的,那么当前递归函数就返回true了,否则最终返回false,参见代码如下:

解法一:

class Solution {
public:
bool pyramidTransition(string bottom, vector<string>& allowed) {
unordered_map<string, unordered_set<char>> m;
for (string str : allowed) {
m[str.substr(, )].insert(str[]);
}
return helper(bottom, "", m);
}
bool helper(string cur, string above, unordered_map<string, unordered_set<char>>& m) {
if (cur.size() == && above.size() == ) return true;
if (above.size() == cur.size() - ) return helper(above, "", m);
int pos = above.size();
string base = cur.substr(pos, );
if (m.count(base)) {
for (char ch : m[base]) {
if (helper(cur, above + string(, ch), m)) {
return true;
}
}
}
return false;
}
};

下面来看一种迭代的写法,这是一种DP的解法,建立一个三维的dp数组,其中dp[i][j][ch]表示在金字塔(i, j)位置上是否可以放字符ch,金字塔的宽和高已经确定了,都是n。每个位置对应着nxn的数组的左半边,如下所示:

F _ _
D E _
A B C

除了底层,每个位置可能可以放多个字符,所以这里dp数组是一个三维数组,第三维的长度为7,因为题目中限定了字母只有A到G共7个,如果dp值为true,表示该位置放该字母,我们根据bottom字符串来初始化dp数组的底层。这里还是需要一个HashMap,不过跟上面的解法略有不同的是,我们建立上方字母跟其能放的基座字符串集合的映射,因为一个字母可能可以放多个位置,所以用个集合来表示。然后我们就开始从倒数第二层开始往顶部更新啦,对于金字塔的每个位置,我们都遍历A到G中所有的字母,如果当前字母在HashMap中有映射,则我们遍历对应的基座字符串集合中的所有字符串,基座字符串共有两个字母,左边的字母对应的金字塔中的位置是(i + 1, j),右边的字母对应的位置是(i + 1, j + 1),我们只要在这两个位置上分别查询对应的字母的dp值是否为true,是的话,说明当前位置有字母可以放,我们将当前位置的字母对应的dp值赋值为true。这样,当我们整个更新完成了之后,我们只要看金字塔顶端位置(0, 0)是否有字母可以放,有的话,说明可以搭出金字塔,返回true,否则返回false,参见代码如下:

解法二:

class Solution {
public:
bool pyramidTransition(string bottom, vector<string>& allowed) {
int n = bottom.size();
vector<vector<vector<bool>>> dp(n, vector<vector<bool>>(n, vector<bool>(, false)));
unordered_map<char, unordered_set<string>> m;
for (string str : allowed) {
m[str[]].insert(str.substr(, ));
}
for (int i = ; i < n; ++i) {
dp[n - ][i][bottom[i] - 'A'] = true;
}
for (int i = n - ; i >= ; --i) {
for (int j = ; j <= i; ++j) {
for (char ch = 'A'; ch <= 'G'; ++ch) {
if (!m.count(ch)) continue;
for (string str : m[ch]) {
if (dp[i + ][j][str[] - 'A'] && dp[i + ][j + ][str[] - 'A']) {
dp[i][j][ch - 'A'] = true;
}
}
}
}
}
for (int i = ; i < ; ++i) {
if (dp[][][i]) return true;
}
return false;
}
};

参考资料:

https://leetcode.com/problems/pyramid-transition-matrix/discuss/113075/DP-O(n2-*-m)

https://leetcode.com/problems/pyramid-transition-matrix/discuss/113036/A-map-based-solution-based-on-memoization

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Pyramid Transition Matrix 金字塔转变矩阵的更多相关文章

  1. LC 756. Pyramid Transition Matrix

    We are stacking blocks to form a pyramid. Each block has a color which is a one letter string, like ...

  2. [LeetCode] 59. Spiral Matrix II 螺旋矩阵 II

    Given an integer n, generate a square matrix filled with elements from 1 to n^2 in spiral order. For ...

  3. [Swift]LeetCode756. 金字塔转换矩阵 | Pyramid Transition Matrix

    We are stacking blocks to form a pyramid. Each block has a color which is a one letter string, like ...

  4. 【LeetCode】756. Pyramid Transition Matrix 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 回溯法 日期 题目地址:https://leetco ...

  5. 【leetcode】756. Pyramid Transition Matrix

    题目如下: We are stacking blocks to form a pyramid. Each block has a color which is a one letter string, ...

  6. LeetCode 73. Set Matrix Zeros(矩阵赋零)

    Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. click ...

  7. LeetCode 54. Spiral Matrix(螺旋矩阵)

    Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral or ...

  8. [LeetCode] 885. Spiral Matrix III 螺旋矩阵之三

    On a 2 dimensional grid with R rows and C columns, we start at (r0, c0) facing east. Here, the north ...

  9. leetcode[73] Set Matrix Zeroes 将矩阵置零

    给定一个矩阵,把零值所在的行和列都置为零.例如: 1 2 3 1 3 1 1 1 操作之后变为 1 3 0 0 0 1 1 方法1: 赋值另存一个m*n的矩阵,在原矩阵为零的值相应置新的矩阵行和列为零 ...

随机推荐

  1. Shiro权限框架(二)

    一.什么是Shiro Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能: 认证 - 用户身份识别,常被称为用户"登录": 授权 - ...

  2. zip详解

    http://www.360doc.com/content/06/0915/14/10610_208147.shtml

  3. 单例模式、简单工厂模式、XML解析

    单例模式: 什么是单例模式? 针对特定问题提出的特定解决方案 为什么使用设计模式? 让程序有更好的可扩展性 在哪里使用? 一般情况下,开发中真正使用设计模式的地方,JVM(虚拟机)底层机制模式 usi ...

  4. mqtt异步publish方法

    Python基于mqtt异步编程主要用到asyncio及第三方库hbmqtt,这里主要介绍mqtt的异步发布及遇到的一些问题. hbmqtt安装很简单,pip hbmqtt install. mqtt ...

  5. Kettle 初始配置数据量类型资源库

    PS:有段时间不使用Kettle了,但总遇到小伙伴问起,写一篇记录下. 文档使用版本:KETTLE 7.0 Kettle资源库可分为文件与数据库,文件型只需要配置好存放路径就行,这边介绍的是配置数据库 ...

  6. 关于如何在mac系统上安装Git并在码市上建立项目

    对Git一窍不通,为了在mac系统上安装Git,查了很多资料,走了很多弯路,一切搞定后发现其实很简单. 1.在https://brew.sh上按要求安装Homebrew. 2.在电脑终端键入brew ...

  7. C语言实现Linux命令——od

    C语言实现Linux命令--od 实现要求: 复习c文件处理内容 编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能 main与其他分开,制作静态库和动态库 编写M ...

  8. 在VS2017下配置OpenGL

    这个方法适合初学者使用,较为简单方便. 第一,你的VS2017一定要安装了C/C++开发组件 可以打开Visual Studio Installer来查看 另外,确定你有安装NuGet包管理器,在单个 ...

  9. python 面向对象之继承与派生

    一:初识继承 1,什么是继承? 继承指的是类与类之间的关系,是一种什么"是"什么的关系,继承的功能之一就是用来解决代码重用问题 继承是一种创建新类的方式,在python中,新建的类 ...

  10. js前端对后台数据的获取,如果是汉字则需要添上引号

    js前端对后台数据的获取,如果是汉字则需要添上引号