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. 第一次使用github、git工具,本地仓库、远程仓库使用

    一次使用git,记录下使用过程...可能还有很多东西可能还没理解,后期理解了再写吧 git是什么.,百度的回答: 一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 使用过程一直在百度 ...

  2. mysql gtid 主从复制

    基于GTID环境搭建主从复制 1.环境 ----------------------------------------------------------| |mysql版本 | 5.7.14 | ...

  3. python爬虫---抓取优酷的电影

    最近在学习爬虫,用的BeautifulSoup4这个库,设想是把优酷上面的电影的名字及链接爬到,然后存到一个文本文档中.比较简单的需求,第一次写爬虫.贴上代码供参考: # coding:utf-8 i ...

  4. 蓝桥杯java历年真题及答案整理1~20.md

    蓝桥杯java历年真题及答案整理(闭关一个月,呕心沥血整理出来的) 1 算法是这样的,如果给定N个不同字符,将这N个字符全排列,最终的结果将会是N!种.如:给定 A.B.C三个不同的字符,则结果为:A ...

  5. java封装的概念

    继承.封装.多态.抽象是面向对象编程的四大基本概念,其中封装尤为重要,因为从我们学习JAVA开始,就基本上接触了封装,因为JAVA中的所有程序都是写在类中的,类也能当做一种封装. 在面向对象中封装是指 ...

  6. python day1 基本语法作业

    一.过7 start =1 while start<=10: if start !=7: print(start) start +=1 二.100以内的和 sum = 0 start = 1 w ...

  7. scrapy 修改URL爬取起始位置

    import scrapy from Autopjt.items import myItem from scrapy.http import Request class AutospdSpider(s ...

  8. 服务器数据恢复方法_存储raid硬盘离线数据恢复案例

    [故障描述]某法院的一台HP-P4500的存储系统,底层是12块1TB的硬盘组的RAID.其中每6个1TB的盘一组,第一组的前面一部分组了一个RAID0+1,是存放HP-P4500嵌入式系统,接着组了 ...

  9. JAVA_SE基础——49.多态的应用

    因为多态对以后开发的重要性,因此我在这里专门开个多态的应用来加深讲解,希望想弄懂多态的同学能耐心看完. 了解了对象多态性后,那么这多态到底有哪些用处了? 下面要求设计一个方法,要求此方法可以接受A类的 ...

  10. Web Api 使用模型验证

    public class Person { public int Id { get; set; } [Required(ErrorMessage = "姓名不能为空啊啊啊!")] ...