LeetCode 3405 统计恰好有 K 个相等相邻元素的数组数目(DP 构造型)


题目概述

我们需要统计长度为 n 的数组 arr 满足如下条件的方案数:

  1. 每个元素在区间 [1, m] 之间
  2. 恰好存在 k 个位置 i (1 ≤ i < n) 满足 arr[i] == arr[i - 1]

也就是说,整个数组中,恰好有 k 个相邻元素对相等。最终返回构造这些数组的方案数,对 1e9 + 7 取模。


示例说明

示例 1:

输入:n = 3, m = 2, k = 1
输出:4
合法数组为:[1,1,2], [1,2,2], [2,1,1], [2,2,1]


问题本质

本题本质上是一个构造型动态规划问题,并非从已有元素中选取,而是一步步构造合法的数组

我们要统计的是:有多少种方法可以构造出一个长度为 n 的数组,包含恰好 k 个“相邻相等对”


动态规划设计

1. 状态定义

dp[i][j] 表示**前 i 个元素中,恰好有 j 个“相邻相等对”**的方案数。

我们从左到右一个个构造数组元素。

  • i 表示数组长度(即前缀长度)
  • j 表示当前构造中已有的相等对数

2. 初始状态

  • dp[1][0] = m:第一个元素有 m 种取值,没有相邻对。

3. 状态转移方程

我们从 dp[i-1][j] 推导出 dp[i][j]

新增元素的两种选择:
  1. 与前一个元素相等

    • 只可选择 1 种值(即与 arr[i-1] 相同)
    • 所以 dp[i][j] += dp[i-1][j-1] * 1
  2. 与前一个元素不同

    • 可选择 m - 1 种不同的值
    • 所以 dp[i][j] += dp[i-1][j] * (m - 1)

4. 完整转移公式

dp[i][j] = dp[i-1][j] * (m - 1)      // 当前位和前一位不相等+ dp[i-1][j-1] * 1          // 当前位和前一位相等(构成一个新对)

注意对 j==0j==i-1 边界的处理。


5. 目标值

我们要求的就是 dp[n][k]


代码实现

C++ 实现(TLE)

class Solution {
public:int countGoodArrays(int n, int m, int k) {const int MOD = 1e9 + 7;vector<int> prev(k + 1), curr(k + 1);prev[0] = m;for (int i = 2; i <= n; ++i) {for (int j = 0; j <= k && j < i; ++j) {long long same = (j > 0 ? prev[j - 1] : 0);long long diff = prev[j] * 1LL * (m - 1) % MOD;curr[j] = (same + diff) % MOD;}prev.swap(curr);}return prev[k];}
};

c++ 优化 1 (TLE)

常规的 O(n * k) 动态规划在极限数据下(n = 1e5)可能会超时。
优化版本:滚动数组 + 预处理 + 取模运算

  • 优化点一:滚动数组 + 二维变一维
    • 原始 dp[i][j] 是二维状态,但只依赖 dp[i-1][*]
    • 可以使用一维滚动数组,空间压缩至 O(k)
  • 优化点二:取模乘法处理要放在中间,避免溢出

状态定义

  • dp[i][j]:长度为 i,且恰好有 j 个相邻相等对的数组数量。

状态转移
我们从 i=2 到 n,转移为:dp[i][j] = dp[i-1][j-1] + dp[i-1][j] * (m - 1)

  • dp[i-1][j-1]:表示第 i 个数与第 i-1 个数相同,构成一个新对,只有 1 种取值(等于前一个)
  • dp[i-1][j] * (m-1):当前数与前一个不同,有 m-1 种取值

初始状态

  • dp[1][0] = m

第一个元素有 m 种选择,不可能形成相邻对

class Solution {
public:int countGoodArrays(int n, int m, int k) {const int MOD = 1e9 + 7;vector<int> dp(k + 1);dp[0] = m;for (int i = 2; i <= n; ++i) {vector<int> newDp(k + 1, 0);for (int j = 0; j <= k && j < i; ++j) {// arr[i] == arr[i-1],增加一个相等对if (j > 0) {newDp[j] = (newDp[j] + dp[j - 1]) % MOD;}// arr[i] != arr[i-1],保持已有对数,新增不同值newDp[j] = (newDp[j] + (long long)dp[j] * (m - 1)) % MOD;}dp = move(newDp);}return dp[k];}
};

c++优化2

使用 快速幂 + 预处理阶乘逆元 求组合数 C(n - 1, g - 1)
使用快速幂计算 (m - 1)^(g - 1)

class Solution {
public:static constexpr int MOD = 1e9 + 7;vector<long long> fact, inv_fact;long long fast_pow(long long base, long long exp) {long long res = 1;while (exp > 0) {if (exp & 1) res = res * base % MOD;base = base * base % MOD;exp >>= 1;}return res;}void init(int n) {fact.resize(n + 1);inv_fact.resize(n + 1);fact[0] = 1;for (int i = 1; i <= n; ++i) {fact[i] = fact[i - 1] * i % MOD;}inv_fact[n] = fast_pow(fact[n], MOD - 2);for (int i = n - 1; i >= 0; --i) {inv_fact[i] = inv_fact[i + 1] * (i + 1) % MOD;}}long long C(int n, int k) {if (k < 0 || k > n) return 0;return fact[n] * inv_fact[k] % MOD * inv_fact[n - k] % MOD;}int countGoodArrays(int n, int m, int k) {init(n);int g = n - k;long long comb = C(n - 1, g - 1);long long ways = comb * m % MOD;ways = ways * fast_pow(m - 1, g - 1) % MOD;return ways;}
};

测试用例建议

输入输出说明
n=1, m=1, k=01唯一合法数组 [1]
n=2, m=1, k=11[1,1]
n=2, m=1, k=00无法构造不同值
n=3, m=2, k=14题目示例
n=100000, m=100000, k=0合法输出测试性能边界

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Elsa Workflows: .NET 的开源工作流引擎简介

文章目录 Elsa Workflows&#xff1a; .NET 的开源工作流引擎核心定位与理念关键特性与优势当前 (Elsa 3) 的已知限制/待完善项总结 Elsa Workflows&#xff1a; .NET 的开源工作流引擎 Elsa Workflows 是一个开源的、模块化的 .NET 库集合&#xff0c;旨在为 .NET 应用程序提…

linux虚拟机yum命令报错解决方案

问题 假如出现了这样的问题&#xff0c;可能是虚拟机yum库存在问题 解决方法 1、打开cmd&#xff0c;输入ssh root地址&#xff0c;比如ssh root192.168.222..111&#xff0c;选yes&#xff0c;输入虚拟机密码 2、使用yum repolist,查看仓库状态&#xff0c;status下面如果是…

C++ 第一阶段 基本语法 - 第一节:变量与数据类型详解

目录 一、变量与数据类型概述 1.1 什么是变量&#xff1f; 1.2 数据类型分类 二、基本数据类型详解 2.1 整型&#xff08;int, short, long&#xff09; 2.1.1 常见整型类型 2.1.2 代码示例 2.1.3 注意事项 2.2 浮点型&#xff08;float, double&#xff09; 2.2.1 浮…

CppCon 2017 学习:CNL: A Compositional Numeric Library

你说的这段关于浮点数的问题总结得很精准&#xff0c;我帮你整理一下&#xff0c;让理解更清晰&#xff1a; The Problem with Floating-Point&#xff08;浮点数的问题&#xff09; 复杂的表示结构 浮点数由符号位 &#xff0c;有效数&#xff08;significand/mantissa&…

linux基础重定向及组合重定向

一、基础重定向操作符 ‌类别‌ ‌操作符‌ ‌含义‌ ‌示例‌ ‌备注‌ ‌标准输出‌ > 覆盖写入 stdout 到文件 ls > file.txt 文件不存在则创建&#xff0c;存在则清空内容 >> 追加 stdout 到文件末尾 date >> log.txt 保留原有内容 ‌标准…

佰力博科技与您探讨铁电分析仪适用场景

铁电分析仪是一种用于测试和研究铁电材料性能的精密仪器&#xff0c;其适用场景非常广泛&#xff0c;涵盖了材料科学、物理学、电子工程等多个领域。 1、材料科学与工程 铁电分析仪广泛应用于铁电材料的研究&#xff0c;包括薄膜、厚膜、块体材料以及电子陶瓷等。它能够测试材料…

JVM 内存模型与垃圾回收机制全解析:架构、算法、调优实践

Java 作为一门面向对象的编程语言&#xff0c;其核心优势之一是 “一次编写&#xff0c;到处运行” 的跨平台特性。这一特性背后&#xff0c;Java 虚拟机&#xff08;JVM&#xff09;扮演着至关重要的角色。JVM 不仅负责解释执行字节码&#xff0c;还通过内存管理和垃圾回收机制…

自然语言处理相关基本概念

基本概念章节总结 一、语言学&#xff08;Linguistics&#xff09; 定义 研究语言的本质、结构和发展规律的科学&#xff0c;涵盖语音、文字、语法等属性。分支包括历时语言学、共时语言学、描述语言学等。 核心内容 分析语言的形态、句法、语义等层面&#xff0c;如词素&…

Vue购物车应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计购物车界面4. 创建Vue实例和数据模型5. 实现购物车功能5.1 从本地存储加载数据5.2 监听数据变化保存到本地存储5.3 实现全选/反选功能5.4 计算选中商品的总价和总数量5.5 实现修改商品数量功能5.6 实现删除商品功能5.7 实现结算功能…

双因子认证如何让Windows系统登录更安全?SLA操作系统双因素认证解决方案深度解析

引言&#xff1a;数字化转型下的身份认证危机 在云计算与远程办公普及的2025年&#xff0c;企业信息系统正面临前所未有的安全挑战。微软Azure Virtual Desktop漏洞事件、Citrix数据泄露等安全事件频发&#xff0c;暴露出传统密码认证体系的致命缺陷。据《2025年云安全威胁报告…

FPGA基础 -- Verilog语言要素之值集合

一、Verilog 值集合&#xff08;Value Set&#xff09; Verilog 是一种面向硬件建模的描述语言&#xff0c;为了更真实地模拟硬件行为&#xff0c;它并不仅仅像 C 语言那样只有 0 和 1 两种值&#xff0c;而是采用了四值逻辑&#xff08;Four-valued logic system&#xff09;…

开源一个芯片自由的脱机下载器

一、什么是脱机下载器 简单来说&#xff0c;脱机下载器就是在不连接电脑、不用专业软件的情况下&#xff0c;也能帮你把程序烧录进芯片的工具。只要插上电源、按个按钮&#xff0c;固件就自动下载进 MCU&#xff0c;非常适合量产、售后、维修等场景。 二、芯片自由的背后&…

Rust 学习笔记:关于模式匹配的练习题

Rust 学习笔记&#xff1a;关于模式匹配的练习题 Rust 学习笔记&#xff1a;关于模式匹配的练习题问题一问题二问题三 Rust 学习笔记&#xff1a;关于模式匹配的练习题 参考视频&#xff1a; https://www.bilibili.com/video/BV1YxojYJESm 问题一 以下代码能否通过编译&…

利用tkinter函数构造MD5加密的可视化操作界面

GitHub文档地址&#xff1a; https://github.com/gao7025/auto_entry_md5.git 引言 利用tkinter构造一个图形界面的创建函数&#xff0c;主要实现了文件选择、MD5加密处理、结果预览和下载等功能。下面是主要涉及的功能模块&#xff1a;主框架、文件选择部分、MD5加密部分、结…

ICEM CFD网格生成 | 基本概念与界面工具

基本概念◆ 名称定义 网格&#xff1a;网格是空间离散的单元&#xff0c;用于如下数值仿真 结构 流体 电磁 其他 单元 0D – 节点单元 质量点 约束&#xff0c;加载位置 1D –线单元 Bars, beams, rods, springs 2D 网格边界 2D – 表面/壳单元 - 四边形 - 三角…

简化您的工作流程:在 Azure 中构建高效的逻辑应用程序

简介 在当今的数字化环境中,自动化工作流程和服务集成对于追求效率和敏捷性的企业至关重要。Azure Logic Apps 使开发人员和 IT 专业人员能够创建集成应用、数据、服务和系统的自动化工作流程。在本文中,我们将逐步讲解使用 Azure 门户创建 Logic Apps 的过程,并通过演示来说…

AI 技术落地实战:开发流程优化、行业场景重塑与前沿应用洞察

在人工智能技术如火如荼发展的当下&#xff0c;AI 工具、大模型以及它们在各行业的应用&#xff0c;正以前所未有的态势重塑着开发者的工作模式和各领域的发展格局。从智能编码助手让编程变得高效便捷&#xff0c;到自动化测试平台提升软件质量&#xff0c;从大模型在垂直行业的…

文本生成AI+图像识别:电商详情页信息提取实战

行业问题&#xff1a;传统采集难以应对“图文视频化”的电商信息 在电商平台不断“视频化”的趋势下&#xff0c;传统的网页采集手段正逐渐失效。以抖音为例&#xff0c;商品信息已不仅限于图文详情&#xff0c;而是通过短视频、图像混排、语音解说等形式呈现。商品的名称、优…

linux权限基础

权限的概念 linux中&#xff0c;权限是用于控制【用户】对 【文件】进行操作控制的工具。用户权限文件权限 用户权限 用户 用户组&#xff1a;具有相同特性的用户的集合体。 文件权限 linux中&#xff0c;一切皆文件&#xff0c;包括普通文件&#xff0c;目录&#xff0c;文件…

让C++处理JSON类型配置文件更轻松-Hjson-cpp详解

让C处理JSON类型配置文件更轻松-Hjson-cpp详解 一、Hjson-Cpp简介Hjson-Cpp简介核心特性安装与集成基本用法示例常用API说明与JSON互转错误处理性能建议高级特性1. 类型安全访问2. 文件操作3. 自定义解析规则 二、使用教程下载使用 一、Hjson-Cpp简介 Hjson-Cpp简介 Hjson-Cp…