【算法学习笔记】29:动态规划中可丢弃状态的维度压缩

2024-08-26 02:20

本文主要是介绍【算法学习笔记】29:动态规划中可丢弃状态的维度压缩,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 动机

当状态 i i i只依赖于前置状态 i − 1 i - 1 i1,并且在计算出状态 i i i之后就可以丢弃状态 i − 1 i - 1 i1时的解时, i − 1 i - 1 i1就成为一个可丢弃的状态,因此就可以将 i i i这个维度直接压缩(省略)掉,用一个变量不停的更新自己就可以了,可以直接节省一个维度的空间占用。

2 例题

2.1 LC1955. 统计特殊子序列的数目

状态表示: f ( i , j ) f(i, j) f(i,j)

  • 集合:对于 0.. i 0..i 0..i组成的子数组, j = 0 j = 0 j=0时表示全0, j = 1 j = 1 j=1时表示正整数个0后接正整数个1, j = 2 j = 2 j=2时表示正整数个0后接正整数个1后接正整数个2,如此子序列组成的集合
  • 属性:Count(集合中元素的数量)

x x x n u m s [ i ] nums[i] nums[i],则有状态转移:

  • x = 0 x = 0 x=0 f ( i , 0 ) = 2 ∗ f ( i − 1 , 0 ) + 1 f(i, 0) = 2 * f(i - 1, 0) + 1 f(i,0)=2f(i1,0)+1,这个 2 ∗ 2 * 2表示 i i i位置的元素选或者不选, + 1 +1 +1表示这个 i i i位置的新的 0 0 0自己组成的新的子序列
  • x > 0 x > 0 x>0 f ( i , x ) = 2 ∗ f ( i − 1 , x ) + f ( i − 1 , x − 1 ) f(i, x) = 2 * f(i - 1, x) + f(i - 1, x - 1) f(i,x)=2f(i1,x)+f(i1,x1)
  • 对于 y ∈ [ 0..2 ] ∣ y ≠ x y \in [0..2]~|~y \neq x y[0..2]  y=x f ( i , y ) = f ( i − 1 , y ) f(i, y) = f(i - 1, y) f(i,y)=f(i1,y)

初始时, f ( 0 , > 0 ) = 0 f(0, >0) = 0 f(0,>0)=0,如果首个元素是 0 0 0那么 f ( 0 , 0 ) = 1 f(0, 0) = 1 f(0,0)=1,否则 f ( 0 , 0 ) = 0 f(0, 0)= 0 f(0,0)=0

class Solution {
public:int countSpecialSubsequences(vector<int>& nums) {constexpr int mod = 1e9 + 7;int n = nums.size();vector<vector<int>> f(n, vector<int>(3, 0));if (0 == nums[0]) f[0][0] = 1;for (int i = 1; i < n; i ++ ){for (int j = 0; j < 3; j ++ )f[i][j] = f[i - 1][j];if (0 == nums[i])f[i][0] = ((2 * f[i - 1][0]) % mod + 1) % mod;elsef[i][nums[i]] = ((2 * f[i - 1][nums[i]]) % mod + f[i - 1][nums[i] - 1]) % mod;}return f[n - 1][2];}
};

这里用了二维数组来存每个状态,但注意到 i i i只依赖 i − 1 i - 1 i1进行状态转移,并且返回的也是 n − 1 n - 1 n1时的结果,所以 i − 1 i - 1 i1是一个可丢弃状态,因此可以进行空间压缩,直接把 i i i这个维度去掉即可:

class Solution {
public:int countSpecialSubsequences(vector<int>& nums) {constexpr int mod = 1e9 + 7;int n = nums.size();int f[3] = {nums[0] ? 0 : 1, 0, 0};for (int i = 1; i < n; i ++ ){if (0 == nums[i])f[0] = ((2 * f[0]) % mod + 1) % mod;elsef[nums[i]] = ((2 * f[nums[i]]) % mod + f[nums[i] - 1]) % mod;}return f[2];}
};

这篇关于【算法学习笔记】29:动态规划中可丢弃状态的维度压缩的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1107274

相关文章

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

MySQL按时间维度对亿级数据表进行平滑分表

《MySQL按时间维度对亿级数据表进行平滑分表》本文将以一个真实的4亿数据表分表案例为基础,详细介绍如何在不影响线上业务的情况下,完成按时间维度分表的完整过程,感兴趣的小伙伴可以了解一下... 目录引言一、为什么我们需要分表1.1 单表数据量过大的问题1.2 分表方案选型二、分表前的准备工作2.1 数据评估

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

浅谈MySQL的容量规划

《浅谈MySQL的容量规划》进行MySQL的容量规划是确保数据库能够在当前和未来的负载下顺利运行的重要步骤,容量规划包括评估当前资源使用情况、预测未来增长、调整配置和硬件资源等,感兴趣的可以了解一下... 目录一、评估当前资源使用情况1.1 磁盘空间使用1.2 内存使用1.3 CPU使用1.4 网络带宽二、

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

使用zip4j实现Java中的ZIP文件加密压缩的操作方法

《使用zip4j实现Java中的ZIP文件加密压缩的操作方法》本文介绍如何通过Maven集成zip4j1.3.2库创建带密码保护的ZIP文件,涵盖依赖配置、代码示例及加密原理,确保数据安全性,感兴趣的... 目录1. zip4j库介绍和版本1.1 zip4j库概述1.2 zip4j的版本演变1.3 zip4