每日一题 —— LC. 790 多米诺和托米诺

news2024/11/15 12:49:34

有两种形状的瓷砖:一种是 2 x 1 的多米诺形,另一种是形如 “L” 的托米诺形。两种形状都可以旋转。

在这里插入图片描述

给定整数 n ,返回可以平铺 2 x n 的面板的方法的数量。返回对 10^9 + 7 取模 的值。

平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺不同,当且仅当面板上有四个方向上的相邻单元中的两个,使得恰好有一个平铺有一个瓷砖占据两个正方形。

示例

在这里插入图片描述

输入: n = 3
输出: 5
解释: 五种不同的方法如上所示。

状态表示

我们从左到右依次扫描每一列,并维护当前列的状态。

这样来定义状态数组:

dp[i][s]表示,前i列已经全部填满,且第i + 1列的填充状态为s时的总方案数。

比如,容易得知,dp[0][0] = 1。什么意思呢?就是把第0列全部填满,且第1列的填充状态为0(一个方块也没有被填充),这种状态可以通过在第0列竖着插入一个2 × 1的多米诺形达到,所以其方案数为1,如下图

image.png

我们继续,看一下在第0列被填满,第1列的状态还可能是哪些呢?比较明显,还有下面3种情况:

image.png

image.png

image.png

这三种情况对应的状态分别是

dp[0][3](3的二进制表示是11,表示第1列的2个方块都被填充了)

dp[0][2](2的二进制表示是10,高位的1表示第1列最顶部的方块被填充了)

dp[0][1](1的二进制表示是01,低位的1表示第1列最底部的方块被填充了)


这4种状态就是我们动态规划的边界条件,或者初始状态。

所以我们的初始状态有:dp[0][0] = dp[0][1] = dp[0][2] = dp[0][3] = 1

接下来看看最终答案是什么。很明显,最终答案应当是,将前n - 1列全部填满,且第n列的填充状态为0时的总方案数,即dp[n - 1][0]

状态转移

然后来看状态转移。

我们初始时先把第0列填满了,所以我们从第1列开始填充,即i1开始循环。
每次枚举,前i - 1列都全部填满时,第i列的状态 (一共只有4种状态) ,然后看看当第i列处于某种状态时,我们可以如何把第i列填满。

  1. i - 1列都填满,且第i列的状态为00时(dp[i - 1][0])

image.png

此时,对于第i列,我们可以

  • 竖着插入一个 2 × 1的多米诺,此时能得到这样的状态:前i列都填满了,且第i + 1列的状态为00(dp[i][0])
  • 横着插入2个2 × 1的多米诺,此时第i + 1列的状态为11(dp[i][3])
  • 插入1个L形的托米诺,由于这个L形的托米诺能够旋转,所以能得到两种i + 1列的状态:0110(dp[i][1]dp[i][2])

所以,由dp[i - 1][0],能够转换到dp[i][0],dp[i][3],dp[i][1],dp[i][2]。也就是说dp[i - 1][0]dp[i][0~3]全部4种状态都有贡献,所以转换到dp[i][0~3]这4种状态时,都要加上dp[i - 1][0]

  1. i - 1列都填满,且第i列的状态为01时(dp[i - 1][1])

image.png

此时,对于第i列,我们可以

  • 横着插入一个2 × 1的多米诺,第i + 1列的状态为10(dp[i][2])
  • 插入一个L形的托米诺,第i + 1列的状态为11(dp[i][3])

所以,由dp[i - 1][1],能够转换到dp[i][2],dp[i][3]

  1. i - 1列都填满,且第i列状态为10时(dp[i - 1][2])

image.png

此时,对于第i列,我们可以

  • 横着插入一个2 × 1的多米诺,第i + 1列的状态为01(dp[i][1])
  • 插入一个L形的托米诺,第i + 1列的状态为11(dp[i][3])

所以,由dp[i - 1][2],能够转换到dp[i][1],dp[i][3]

  1. i - 1列都填满,且第i列状态为11时(dp[i - 1][3])

image.png

此时,对于第i列,我们无法再插入任何方块。只能得到第i + 1列的状态为00(dp[i][0])

所以,由dp[i - 1][3],能够转换到dp[i][0]

我们将上面,dp[i - 1][0~3]dp[i][0~3]的关系,进行一下整理,容易得到状态转移方程如下

  • dp[i][0] = dp[i - 1][0] + dp[i - 1][3]
  • dp[i][1] = dp[i - 1][0] + dp[i - 1][2]
  • dp[i][2] = dp[i - 1][0] + dp[i - 1][1]
  • dp[i][3] = dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2]

代码

于是就能写出如下代码

typedef long long LL;
const int MOD = 1e9 + 7;
class Solution {
public:
    int numTilings(int n) {
        vector<vector<LL>> dp(n, vector<LL>(4, 0));
        // dp[i][s]表示前i列已经填好, 伸出去第i + 1列情况为 s 时的方案数
        dp[0][0] = dp[0][1] = dp[0][2] = dp[0][3] = 1;
        for (int i = 1; i < n; i++) {
            dp[i][0] = (dp[i - 1][0] + dp[i - 1][3]) % MOD;
            dp[i][1] = (dp[i - 1][0] + dp[i - 1][2]) % MOD;
            dp[i][2] = (dp[i - 1][0] + dp[i - 1][1]) % MOD;
            dp[i][3] = (dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2]) % MOD;
        }
        // 答案返回前n - 1列已经全部填好, 且伸出去第i + 1列情况为0时的方案数
        return (int) dp[n - 1][0];
    }
};

并且由于dp[i][0~3]只依赖于dp[i - 1][0~3],还能用滚动数组进行优化

typedef long long LL;
const int MOD = 1e9 + 7;
class Solution {
public:
    int numTilings(int n) {
        LL s0, s1, s2, s3;
        s0 = s1 = s2 = s3 = 1;
        for (int i = 1; i < n; i++) {
            LL t0 = (s0 + s3) % MOD;
            LL t1 = (s0 + s2) % MOD;
            LL t2 = (s0 + s1) % MOD;
            LL t3 = (s0 + s1 + s2) % MOD;
            s0 = t0;
            s1 = t1;
            s2 = t2;
            s3 = t3;
        }
        return (int) s0;
    }
};

PS: 这些都是俺从y总那里学到的(●’◡’●)

y总牛逼!(❤ ω ❤)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/12492.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据集成平台关于【源平台调度任务生命周期】

任务调度者 调度事件生产任务调度任务池-异步
AsynDispatcher --source 实例化适配器执行 消费任务实例化集成应用 DataHub Instance
handleSourceDispatch()依赖注入集成方案适配器调度条件检查执行适配器调度方法联动其它方案调度任务 SourceEvent 适配器调度周期 初始化…

化合物应用 | 动物实验溶剂选择

在给药时为了实现药物准确运送到动物体内、减少溶剂本身的副作用和毒性等的目标&#xff0c;需要选择合适的溶剂配方。溶剂的理化性质&#xff0c;如 pH、粘稠度、渗透压等都会对给药产生影响&#xff0c;需要慎重考虑。例如粘稠度过高可能会导致注射用针头的堵塞&#xff0c;粘…

作为新人,如何快速融入新团队?用好这8个点

大家好&#xff0c;之前在公司调岗&#xff0c;转到了新团队。 从一开始的不适应、不习惯&#xff0c;到现在的逐步习惯&#xff0c;真的就是和那句老话说的一样「有压力才会有成长」&#xff0c;下面晨光会结合在新团队学到的内容进行分享。 文章分为以下几个部分&#xff1…

通过云速搭CADT实现云原生分布式数据库PolarDB-X 2.0的部署

云速搭 CADT 是一款为上云应用提供自助式云架构管理的产品&#xff0c;显著地降低应用云上管理的难度和时间成本。本产品提供丰富的预制应用架构模板&#xff0c;同时也支持自助拖拽方式定义应用云上架构&#xff1b;支持较多阿里云服务的配置和管理。用户可以方便的对云上架构…

人力资源数字化转型,是企业高质量发展的关键

情景一 中层管理者&#xff0c;每天不是在开会&#xff0c;就是在帮下属解决问题&#xff0c;时间被搞的一团乱麻&#xff1b; 为了顺利推进项目&#xff0c;总是把自己逼成卷王&#xff0c;即使如此也没能挽救业绩下滑的命运。 情景二 由于业务能力出色被提拔带团队的新晋…

计算机网络-传输层(UDP协议报文格式,伪首部,UDP校验过程)

文章目录1. UDP协议UDP报文格式UDP校验过程1. UDP协议 UDP只在IP数据报服务之上增加了很少功能&#xff0c;即复用分用和差错检测功能。 UDP的主要特点: UDP是无连接的&#xff0c;减少开销和发送数据之前的时延。 UDP使用最大努力交付&#xff0c;即不保证可靠交付。 UDP是…

webpack5 Preload / Prefetch解决按需求加载速度

代码分离 | webpack 中文文档webpack 是一个模块打包器。它的主要目标是将 JavaScript 文件打包在一起&#xff0c;打包后的文件用于在浏览器中使用&#xff0c;但它也能够胜任转换&#xff08;transform&#xff09;、打包&#xff08;bundle&#xff09;或包裹&#xff08;pa…

vue_mixin混入

目录官网基本概念什么是Mixin混入和组件的区别混入和vuex的区别mixin的优点mixin的缺点使用mixin语法mixin局部混入-mixins全局混入-Vue.mixin方法(不推荐)mixin与组件合并逻辑[1]data数据总结举例说明[2]methods方法总结举例说明[3]生命周期函数总结举例说明问题&#xff1a;一…

Linux 进程信号

目录 一.信号 1.介绍 2.信号概念 3.查看系统定义的信号列表 4.信号处理的方式 二.信号产生前 1.用户层产生信号的方式 三.产生信号 1.通过按键产生信号 2.调用系统函数向进程发信号 &#xff08;1&#xff09;kill &#xff08;2&#xff09;raise &#xff08;…

大学生WEB前端静态网页——旅游介绍35页 响应式,

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 游景点介绍 | 旅游风景区 | 家乡介绍 | 等网站的设计与制作| HTML期末大学生网页设计作业&#xff0c;Web大学生网页 HTML&#xff1a;结构 CSS&…

Android 高通 Launcher3 添加桌面快捷方式

1、最近接到产测一个需求&#xff0c;需要在首页WorkSpace添加产测apk快捷方式&#xff0c;于是乎我去查看了一下Android12的源码&#xff0c;包名/build3/zm/Em_TK1080/EM_TK1080_prj/EM_TK1080_prj/qssi12/packages/apps/Launcher3/res/xml 主要修改文件 default_workspace…

TCP程序设计基础

TCP网络程序设计是指用Socket类编写通信程序。利用TCP协议进行通信的两个应用程序是有主次之分的&#xff0c;一个称为服务器程序&#xff0c;另一个称为客户机程序。两者的功能和编写方法不大一样。服务器端与客户端的交互过程如图所示&#xff1a; 1. InetAddress类 java.…

用 Kafka + DolphinDB 实时计算K线

Kafka 是一个高吞吐量的分布式消息中间件&#xff0c;可用于海量消息的发布和订阅。 当面对大量的数据写入时&#xff0c;以消息中间件接收数据&#xff0c;然后再批量写入到时序数据库中&#xff0c;这样可以将消息中间件的高并发能力和时序数据库的高吞吐量联合起来&#xf…

关于报表打印

1 分页策略 分页与打印时密切相关的&#xff0c;皕杰报表提供了四种分页策略&#xff0c;即按纸张大小分页、按数据行数分页、按数据列数分页、用户自定义分页和不分页。分页由2个因素来控制&#xff0c;一个每个页面的大小&#xff0c;另外一个是分页顺序&#xff08;打印顺序…

如何将抓取下来的unicode字符串转换为中文

如果抓取的数据是json数据&#xff0c;那么直接将抓取的数据用json格式输出出来就行了。如下: response requests.get(url, headersheaders).json()那么大家遇到如下的unicode字符串的是如何解决的呢&#xff1f;如下图所示&#xff1a; 相信大家遇到这种一定会抓狂吧&#…

一种改进Harris算子的角点特征检测研究-含Matlab代码

⭕⭕⭕⭕ 目 录 ⭕⭕⭕⭕✅ 一、引言✅二、Harris角点检测算法✅三、角点检测实验验证✅四、参考文献✅五、Matlab代码获取✅ 一、引言 将图像中灰度变化剧烈或者在图像边界上曲率变化较大的点称为角点。角点检测对于工件图像的特征点定位有着重要作用&#xff0c;在进行工件的…

MySQL高级学习笔记(一)

文章目录MySQL高级学习笔记(一)1.索引1.1索引概述1.2索引优势劣势1.3索引结构1.3.1BTREE 结构1.3.2BTREE 结构1.3.3MySQL中的BTree1.4索引分类1.5索引语法1.5.1 创建索引1.5.2 查看索引1.5.3 删除索引1.5.4 ALTER命令1.6 索引设计原则2.视图概述2.1创建或者修改视图2.2查看视图…

【python3】5.正则表达式

本学习内容总结于莫烦python:5.正则表达式 https://mofanpy.com/tutorials/python-basic/interactive-python/regex5.正则表达式 本章较为重要&#xff0c;单独拿出来成章了 正则表达式是一个特殊的字符序列&#xff0c;它能帮助你方便的检查一个字符串是否与某种模式匹配。 …

【数据结构】栈和队列的实现(C语言)

前言 栈和队列都是重要的线性结构&#xff0c;即在使用层面上收到限制而发挥特殊作用的线性表。掌握这两种结构在不同情景下亦会发挥重要作用。 栈 定义 栈保持着后进先出的原则&#xff0c;正因如此在插入数据的时候要求只能从一段插入&#xff0c;称为栈顶&#xff1b;相反另…

Arduino与Proteus仿真实例-电子相册仿真

电子相册仿真 本次实例将仿真如何从SD卡读取BMP格式图像并在ILI9341驱动器的LCD显示屏上显示。 1、仿真电路原理图 在仿真电路原理图中,SD卡通过SPI方式连接,ILI9341 LCD显示屏也是通过SPI方式连接。SD卡的CS引脚连接Arduino Mega2560的SS引脚(Pin10),显示屏的CS引脚连接…