Leetcode 3130. Find All Possible Stable Binary Arrays II

  • Leetcode 3130. Find All Possible Stable Binary Arrays II
    • 0. 序言
    • 1. 算法思路
    • 2. 代码实现
      • 1. 第一版本
      • 2. 第二版本
      • 3. 第三版本
      • 4. 第四版本
    • 3. 算法优化
      • 1. 算法实现一
      • 2. 算法实现二
  • 题目链接:3130. Find All Possible Stable Binary Arrays II

0. 序言

这道题和题目3129本质上就是一道题目,唯一的差别就是取值范围的差异,题目3129的范围在 [ 1 , 200 ] [1,200] [1,200],而这道题在 [ 1 , 1000 ] [1, 1000] [1,1000],因此复杂度会更高。

很不幸,我只搞定了题目3129,而这道题则是死活都没有搞定,最后是看了一下题目3129当中其他大佬们的高效率算法之后改写了一下通过了最后的测试,不过不幸的是,具体到思路上依然是没有看懂,真的是有点伤……

所以,这里的话我会现在前两部分讲一下我自己的算法思路,以及为了提升算法效率而做的优化,总体来说的话,在题目3129当中将算法效率提升了10倍左右,耗时从3727ms降至574ms,不过不幸的是依然无法通过题目3130的测试样例……

因此,如果有读者对这部分内容不感兴趣的话可以直接跳到第三部分看一下大佬们的高效算法即可。

1. 算法思路

这一题我整体的算法思路是当做一个数学上的排列组合问题来做的,显然,如果0和1的个数 n , m ≤ l i m i t n, m \leq limit n,mlimit的话,那么显然我们可以直接给出答案 C n + m n C_{n+m}^{n} Cn+mn

但问题就在于如果有 n , m > l i m i t n, m > limit n,m>limit的情况,此时就不能直接用数学方法解了,本来考虑如果将 l i m i t + 1 limit+1 limit+1(不妨简记 l i m i t + 1 = k limit+1=k limit+1=k)个元素进行绑定然后填充的方式,倒是可以直接计算组合数为: C n + m − k n ⋅ ( n + 1 ) C_{n+m-k}^{n} \cdot (n+1) Cn+mkn(n+1)

不过这种情况仅限于 n < k n < k n<k k < m < 2 k k < m < 2k k<m<2k的情况,即要确保不可能存在两个组内的元素均不少于 k k k个,否则就会出现重复计数的情况。

最后,关于其他的情况,我们就是能用动态规划进行暴力求解了,就很繁琐。

2. 代码实现

1. 第一版本

首先,我们给出我们的第一版本的代码实现如下:

MOD = 10**9+7
FACTORIALS = [1 for _ in range(401)]
for i in range(1, 401):FACTORIALS[i] = i * FACTORIALS[i-1] % MODdef rev(x):return pow(x, -1, MOD)def C(n, m):if m < 0:return 0return FACTORIALS[n] * rev(FACTORIALS[m]) * rev(FACTORIALS[n-m]) % MODclass Solution:def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:@lru_cache(None)def dp(n,m,k,p):# n -> zero, m -> one, k -> pre count, p -> pre elementif n + (1-p) * k > limit * (m+1) or m + p * k > limit * (n+1):return 0elif n + (1-p) * k <= limit and m + p * k <= limit:ans = C(n+m, n)elif p == 0 and n + k <= limit and m > limit and m <= 2 * limit:ans = C(n+m, n) - C(n+m-limit-1, n) * (n+1)elif p == 1 and n > limit and m + k <= limit and n <= 2 * limit:ans = C(n+m, n) - C(n+m-limit-1, m) * (m+1)else:ans = 0if k*(1-p)+1 <= limit:ans = (ans + dp(n-1, m, k*(1-p)+1, 0)) % MODif k*p+1 <= limit:ans = (ans + dp(m-1, n, k*p+1, 0)) % MODreturn ans % MODans = dp(zero, one, 0, 0)return ans

这个实现基本就是翻译了一下我们的上述实现,在题目3129上的评测结果如下:耗时3727ms,占用内存756.5MB。

2. 第二版本

然后,我们注意到这里的n, m事实上是完全等价的,因此,我们就可以取消掉p这个元素,也就是无需再记录前一个元素是什么,直接对换n,m的值即可,选用是默认从n当中进行元素选择作为开头,这样就可以进一步提升cache的利用率了。

给出第二版代码实现如下:

MOD = 10**9+7
FACTORIALS = [1 for _ in range(401)]
for i in range(1, 401):FACTORIALS[i] = i * FACTORIALS[i-1] % MODdef rev(x):return pow(x, -1, MOD)def C(n, m):if m < 0:return 0return FACTORIALS[n] * rev(FACTORIALS[m]) * rev(FACTORIALS[n-m]) % MODclass Solution:def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:@lru_cache(None)def dp(n,m,k):if n + k > limit * (m+1) or m > limit * (n+1):return 0elif n + k <= limit and m <= limit:ans = C(n+m, n)elif n + k <= limit and m > limit and m <= 2 * limit:ans = C(n+m, n) - C(n+m-limit-1, n) * (n+1)else:ans = dp(m-1, n, 1)if k+1 <= limit:ans = (ans + dp(n-1, m, k+1)) % MODreturn ans % MODans = dp(zero, one, 0)return ans

提交代码评测得到:耗时3157ms,占用内存684.4MB。

3. 第三版本

然后,我们注意到这个k也很碍事,既然n,m的地位完全等价了,我们只需要默认每次都必须从n当中选择1到limit个元素即可,这样就可以去掉k这个参数了,可以进一步优化cache。

MOD = 10**9+7
FACTORIALS = [1 for _ in range(401)]
for i in range(1, 401):FACTORIALS[i] = i * FACTORIALS[i-1] % MODdef rev(x):return pow(x, -1, MOD)def C(n, m):if m < 0:return 0return FACTORIALS[n] * rev(FACTORIALS[m]) * rev(FACTORIALS[n-m]) % MODclass Solution:def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:@lru_cache(None)def dp(n,m):if n == 0:return 0elif m == 0:return 1 if n <= limit else 0elif n > limit * (m+1) or m > limit * n:return 0elif n <= limit and m <= limit:ans = C(n+m-1, m)elif n <= limit and m > limit and m <= 2 * limit:ans = C(n+m-1, m) - C(n+m-limit-2, n-1) * nelse:ans = 0for i in range(1, min(limit, n) + 1):ans = (ans + dp(m, n-i))return ans % MODans = (dp(zero, one) + dp(one, zero)) % MODreturn ans

提交代码评测得到:耗时707ms,占用内存32.1MB。

4. 第四版本

最后,我们还对上述 C n m C_{n}^{m} Cnm的实现进行了一下优化,具体来说的话就是每次都算pow(n, -1 MOD)太耗时了,因此我们也像阶乘一样预先算好保存在一个数组当中即可。

给出python代码实现如下:

MOD = 10**9+7
FACTORIALS = [1 for _ in range(401)]
for i in range(1, 401):FACTORIALS[i] = i * FACTORIALS[i-1] % MODInv_FACTORIALS = [pow(x, -1, MOD) for x in FACTORIALS]def C(n: int, m: int):if m < 0:return 0return (FACTORIALS[n] * Inv_FACTORIALS[m] * Inv_FACTORIALS[n-m]) % MODclass Solution:def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:@lru_cache(None)def dp(n,m):if n == 0:return 0elif m == 0:return 1 if n <= limit else 0elif n > limit * (m+1) or m > limit * n:return 0elif n <= limit and m <= limit:ans = C(n+m-1, m)elif n <= limit and m > limit and m <= 2 * limit:ans = C(n+m-1, m) - C(n+m-limit-2, n-1) * nelse:ans = 0for i in range(1, min(limit, n) + 1):ans = (ans + dp(m, n-i))return ans % MODans = (dp(zero, one) + dp(one, zero)) % MODreturn ans

提交代码评测得到:耗时574ms,占用内存32MB。

3. 算法优化

不过可惜的是,即便如此,上述的算法依然无法通过题目3130的测试样例,还是会出现超时的情况。因此在下面的小节里面,我们摘录了两个大佬的两个算法实现,分别来自题目3129和题目3130的解答当中耗时最优的方法,然后稍微用我自己感觉更好理解的方式稍微翻译了一下,虽然我自己依然没有完全看明白具体的数学含义就是了。

不过插句题外话,虽然代码实现两个算法不太一样,不过从具体的思路以及参数计算来看,我觉得这俩实现很可能来自同一个大佬……

只能说,大佬牛逼……

1. 算法实现一

MOD = 10**9+7
FACTORIALS = [1 for _ in range(1001)]
for i in range(1, 1001):FACTORIALS[i] = i * FACTORIALS[i-1] % MODInv_FACTORIALS = [pow(x, -1, MOD) for x in FACTORIALS]def C(n: int, m: int):if m < 0:return 0return (FACTORIALS[n] * Inv_FACTORIALS[m] * Inv_FACTORIALS[n-m]) % MODclass Solution:def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:ans = 0N = zero + onemin_zero_group = (zero - 1) // limit + 1min_one_group = (one - 1) // limit + 1@lru_cache(None)def count(n, g, k):ans = C(n+g-1, g-1)r, flag = 1, -1while n - r * (k+1) >= 0:ans = (ans + flag * C(n - r*(k+1) + g-1, g-1) * C(g, r)) % MODr += 1flag *= -1return ansfor n in range(min_zero_group, zero+1):for m in range(n-1, n+1+1):if m < min_one_group or m > one:continueflag = 1 if n != m else 2ans = (ans + flag * count(zero-n, n, limit - 1) * count(one-m, m, limit - 1)) % MODreturn ans % MOD

提交代码评测得到:耗时72ms,占用内存17.1MB。

2. 算法实现二

MOD = 10**9+7
FACTORIALS = [1 for _ in range(1001)]
for i in range(1, 1001):FACTORIALS[i] = i * FACTORIALS[i-1] % MODInv_FACTORIALS = [pow(x, -1, MOD) for x in FACTORIALS]def C(n: int, m: int):if m < 0:return 0return (FACTORIALS[n] * Inv_FACTORIALS[m] * Inv_FACTORIALS[n-m]) % MODclass Solution:def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:ans = 0N = zero + onemin_zero_group = (zero - 1) // limit + 1min_one_group = (one - 1) // limit + 1def count(n, g, k):ans = C(n+g-1, g-1)r, flag = 1, -1while n - r * (k+1) >= 0:ans = (ans + flag * C(n - r*(k+1) + g-1, g-1) * C(g, r)) % MODr += 1flag *= -1return ansfor n in range(min_zero_group, zero+1):for m in range(n-1, n+1+1):if m < min_one_group or m > one:continueflag = 1 if n != m else 2ans = (ans + flag * count(zero-n, n, limit - 1) * count(one-m, m, limit - 1)) % MODreturn ans % MOD

提交代码评测得到:耗时94ms,占用内存16.7MB。

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

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

相关文章

已经有 Prometheus 了,还需要夜莺?

谈起当下监控&#xff0c;Prometheus 无疑是最火的项目&#xff0c;如果只是监控机器、网络设备&#xff0c;Zabbix 尚可一战&#xff0c;如果既要监控设备又要监控应用程序、Kubernetes 等基础设施&#xff0c;Prometheus 就是最佳选择。甚至有些开源项目&#xff0c;已经内置…

LoRA的原理简介

在文章开始前先澄清一个概念&#xff0c;需要区分形近的单词"LoRa"&#xff08;long range&#xff09;&#xff0c;这是一项通信技术。熟悉物联网行业的朋友相对会比较熟悉LoRa这项技术&#xff0c;因为有些设备比如电梯的控制就使用了这个技术进行本地数据和命令的…

小红书释放被封手机号 无限注册

前几年抖音也可以释放被封手机号 那时候都不重视 导致现在被封手机号想释放 基本不可能的 或者就是最少几百块 有专业的人帮你通过某些信息差释放 本教程是拆解 小红书被封手机号怎么释放&#xff0c;从今年开始&#xff0c;被封的手机号无法注销了 所以很困扰 那么本教程来…

TypeScript中的数据选择艺术:pick和omit操作入门

引言 标题&#xff1a;TypeScript中的数据选择艺术&#xff1a;pick和omit操作入门简短介绍&#xff1a;探索TypeScript中的实用工具类型Pick和Omit&#xff0c;它们可以帮助你从现有类型中选择或排除属性&#xff0c;简化你的代码并提高类型安全性。 背景知识 易于理解的解…

基于一种改进小波阈值的微震信号降噪方法(MATLAB)

微震是指岩体由于在人为扰动或自然原因下受力变形&#xff0c;发生破裂过程中能量积聚而释放的弹性波或应力波。微震信号具有信噪比低、不稳定性、瞬时性和多样性等特点。因此&#xff0c;在任何损坏之前都会出现微小的裂缝&#xff0c;这种微小的裂缝是由岩层中应力和应变的变…

PPT职场课:话术+技巧+框架+案例,告别只会念PPT不会讲(8节课)

课程目录 001-讲PPT如何开场及导入?5个简单实用的方法.mp4 002-讲PPT如何过渡衔接结尾?6类话术争来就用.mp4 003-掌握这3个逻辑表达万能框架&#xff0c;搞定98的PPT.mp4 004-学会这3种PPT结构讲解技巧告别只会念不会讲(上).mp4 005-学会这3种PPT结构讲解技巧告别只会念…

Logstash分析MySQL慢查询日志实践

删除匹配到的行&#xff0c;当前行信息不记录到message中

106网页短信群发平台

什么是106网页短信群发平台&#xff1f; 106网页短信群发平台是一种便捷的在线群发工具&#xff0c;通过该平台用户可以方便地向大量的手机号码*。相比传统的群发方式&#xff0c;106网页群发平台具有更高效、更便捷的特点。 为什么选择106网页短信群发平台&#xff1f; 高效快…

浙大×移动云,携手点亮AI新时代

近年来&#xff0c;中国移动依托强大的算网资源优势&#xff0c;围绕大模型训练、推理和应用三大场景&#xff0c;打造了一站式智算产品体系。该体系旨在为客户提供覆盖资源、平台、应用的AI全链路服务。目前&#xff0c;一站式智算产品体系已在浙江大学智算中心和许昌中原智算…

C++:编程界的王者,引领未来的创新之路

在编程语言的浩瀚星空中&#xff0c;C犹如一颗耀眼的恒星&#xff0c;以其卓越的性能、深厚的底蕴和广泛的应用领域&#xff0c;持续引领着编程界的发展。它不仅在当下拥有无可替代的地位&#xff0c;更在未来展现出无限的潜力和可能性。 一、C&#xff1a;编程界的王者风范 …

事务transaction与其的acid特性

DDL DML CREATE TABLE student (id int(11) NOT NULL AUTO_INCREMENT COMMENT 学号,createDate datetime DEFAULT NULL COMMENT 创建时间,modifyDate datetime DEFAULT NULL COMMENT 修改时间,userName varchar(30) NOT NULL COMMENT 学生名称,pwd varchar(36) DEFAULT NULL …

若依框架dialog弹窗取消点击空白出关闭

如果想全局取消的话就找到main.js在里面加上下面的一行代码&#xff0c;添加完成之后记得清楚浏览器缓存重新加载js文件。 Element.Dialog.props.closeOnClickModal.default false;如果想指定某个弹窗取消点击空白处关闭&#xff0c;那么就找到那个弹窗加上。添加完毕之后刷新…

【python】基于岭回归算法对学生成绩进行预测

前言 在数据分析和机器学习领域&#xff0c;回归分析是一种预测连续数值的监督学习技术。当数据特征与目标变量之间存在线性关系时&#xff0c;线性回归模型尤其有用。然而&#xff0c;当特征数量多于样本数量&#xff0c;或者特征之间存在多重共线性时&#xff0c;普通最小二…

unaipp推荐算法的汽车租赁系统zaxzu 微信小程序hbuiderx

随着现代汽车租赁管理的快速发展&#xff0c;可以说汽车租赁管理已经逐渐成为现代汽车租赁管理过程中最为重要的部分之一。但是一直以来我国传统的汽车租赁管理并没有建立一套完善的行之有效的汽车租赁管理系统&#xff0c;传统的汽车租赁管理已经无法适应高速发展&#xff0c;…

基于SpringBoot+Vue点餐系统设计和实现(源码+LW+部署讲解)

&#x1f339;作者简介&#xff1a;✌全网粉丝10W&#xff0c;前大厂员工&#xff0c;多篇互联网电商推荐系统专利&#xff0c;现有多家创业公司&#xff0c;致力于建站、运营、SEO、网赚等赛道。也是csdn特邀作者、博客专家、Java领域优质创作者&#xff0c;博客之星、掘金/华…

1.02.02 虚拟化与容器化Docker环境搭建

1.02.02 虚拟化与容器化Docker环境搭建 ******************************************************************************* *******************************************************************************

nginx的应用部署nginx

这里写目录标题 nginxnginx的优点什么是集群常见的集群什么是正向代理、反向代理、透明代理常见的代理技术正向代理反向代理透明代理 nginx部署 nginx nginx&#xff08;发音同enginex&#xff09;是一款轻量级的Web服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&…

「Java开发指南」如何用MyEclipse搭建GWT 2.1和Spring?(一)

本教程将指导您如何生成一个可运行的Google Web Toolkit (GWT) 2.1和Spring应用程序&#xff0c;该应用程序为域模型实现了CRUD应用程序模式。在本教程中&#xff0c;您将学习如何&#xff1a; 安装Google Eclipse插件为GWT配置一个项目搭建从数据库表到一个现有的项目GWT编译…

学习前端第二十九天(可迭代对象,映射和解构【弱】,Object.keys values)

一、可迭代对象 1、Symbol.iterator方法&#xff0c;使对象可迭代 [Symbol.iterator]() {let i 5;return {next() {i--;return { done: !i, value: i }}}} next&#xff08;&#xff09;方法返回的结果的格式必须是{done&#xff1a;Boolean&#xff0c;value&#xff1a;a…

有关while((c=getchar())!=\n)和while((ch=getchar()!=EOF))

Ⅰ 详解 while((cgetchar())!\n) \n是回车符&#xff0c; ch getchar()从键盘输入一个字符&#xff0c; 整句话的意思就是&#xff0c;当从键盘输入回车符时&#xff0c;循环结束 while((chgetchar()!EOF)) 1.分别介绍getchar和EOF int getchar(void) 使用键盘输入字符&a…