双色塔问题,读懂屎山代码

现在有红,绿两种颜色的石头,现在我们需要用这两种石头搭建一个塔,塔需要满足如下三个条件: 

1. 第 1 层应该包含1块石头,第2层应该包含两块,第 i 层需要包含 i 块石头。

2. 同一层的石头应该是同一个颜色(红或绿)。

3. 塔的层数尽可能多。 问在满足上面三个条件的前提下,有多少种不同的建造塔的方案,当塔中任意一个对应位置的石头颜色不同,我们就认为这两个方案不相同。石头可以不用完。

数据范围:红绿颜色石头数量满足  0≤a,b≤2×105  ,   a+b≥1 

给出红石头和绿石头的个数,请输出有多少种叠法

说实话,大家都不喜欢看公式,太难懂,程序员大佬普遍不善表达,我个人也是看了一晚上才大概明白这个题的正确答案是甚么意思,在这里就不贴代码了,只讲一下大体的思路,应该能读的更清晰一些。以及想吐槽一下,希望程序员*********把代码写的清晰易懂一些。

先说一下自己怎么做的:没怎么学过动态规划,考虑的是用递归。定义solution(a,b,i),a和b分别表示目前红绿石头分别还剩下多少,i表示我目前数到了第i层,这个函数return的就是目前叠到第i层的时候,还剩a个红石头和b个绿石头,会有多少种解决方案。定义这个函数的作用就是不停地往下一层去数,直到进入最深层

写这个问题先定义递归的尽头,当两种颜色的石头的数量都小于需要的石头数量i时,达到尽头了,这种情况下返回1。其实这一步就很完美了,但是不符合条件3,也就是说如果我们这么做的话,会产生一些比较矮的塔。那么我在这里修改为返回 1,i-1两个输出。也就是同时返回个数和这种情况下能够达到的最大层数,以进行后续的比较。

而在else的情况下,分为三种情况:只有红宝石够用,只有绿宝石够用和两种宝石都够用。

只有红宝石够用时,问题转化为solution(a-i,b,i+1),即本层只能使用红宝石

只有绿宝石够用时,问题转化为solution(a,b-i,i+1),即本层只能使用绿宝石

两种宝石都够用时,问题转化为solution(a-i,b,i+1)和solution(a,b-i,i+1),但这里不能直接相加,因为要比较深度,两种情况的输出要在比较之后进行处理,再return

而第一层为solution(G,R,1),此处为函数的入口。

其实这么做基本上很完美了,但是运行速度较慢,提交的时候是不合格的。下面分享大佬的答案。

此题动态规划整理:最重要的是定义数组以及状态转移方程。

如何定义数组?这里大佬使用的是array[i][j]的形式,其含义为堆到第i层时,已经用了j个绿宝石。此处怎么想到的我也不太好讲,但是你要是问为什么不考虑红宝石呢,我会说后面会使用限定条件来让红宝石达到够用的目的。

核心思路仍然为通过前一层来推导当前层,假设前一层已经叠好。这个想法依赖于甚么呢?依赖于我第一层的结果是很好得到的,正常情况下:

array[1][0]=1,我第一层不用绿宝石,那么结果为1

array[1][1]=1,我第一层用绿宝石,那么结果为1

那么假设我已有array[i][*]的全部信息,我如何获得array[i+1][*]?很简单,我在i+1层,要么我就用绿宝石,要么我就不用,当然此处会写判定条件,看看宝石够不够用。

所以说,当前层只需要获得前一层的信息即可,这样的话我只需要2行1维数组,一行1维数组在本次循环中为当前行,那么在下一次循环中就可以视为上一行。此处是一个节省空间的技巧

int one = lev % 2; int two = (lev - 1) % 2;

这个塔理想状况下能达到多少层?假设每一层都有石头可以叠,而石头总数又不超过实际宝石的总数,就能写出level的定义了:

while (sum <= R + G) { level++; sum += level; }

下面开始真正的计算,此处开始一个超大循环,为当前进行到的层数的叠加

内层循环为当前层已经使用了的绿宝石数的增加,计算在当前层的当前已使用绿宝石数的情况下,会出现多少种方案,上文已给出推导方式,限定条件的核心思想为已使用的绿宝石与红宝石的数量均够用

最后,循环将推导出最深层的结果,即最深层的组合方式,将最深层的array[][]的那一行进行求和,即为结果。

源码详见:https://codeleading.com/article/2412986569/

难点还是在于怎么定义array数组,此处为只考虑一种宝石的消耗数量,而另一种宝石的消耗后续会用条件来限定,因此可以不再考虑。这种思路可以去参考。状态转移不是特别困难。希望自己能把这个问题以一种不太程序员的方式讲明白。

#算法刷题笔记#
全部评论

相关推荐

2025-12-31 19:23
已编辑
门头沟学院 Java
ssob是已读不回的,字节是压根不敢投的,简历是反反复复改了N遍的,八股是永远背不完的😅😅😅扯远了,道心破碎了,把简历发出来让大伙先看看笑话。再说正事。寒假日常实习还是很难找,连个面试都难约,我不是个例,这是网上普遍反映。不报希望了,趁着2、3月前赶紧做些什么才是。扔几个碎碎念:1.这破简历还能怎么改?写到什么程度才能过实习岗筛选?广大牛友来锐评一下2.火速辅修go,是否可行目前看来是学习成本最小的。首先,很多go实习岗位已经明确要求掌握gin等技术栈,拿java简历投go的时代已经过去了。其次,很多后端的东西,MySQL、Redis这些都是通用的,不用重新学。所以这个问题就具体为:2.1&nbsp;java&amp;go混血简历怎么写第一个项目,仿大麦的微服务,不太好改。因为有用到Redisson、AOP、SpringAI这些java强相关的东西,包装成go需要替换这些方案。第二个,点评魔改。应该可以包装成go,github上也有人用go重写过。2.2&nbsp;java&amp;go通用的轮子RPC直接pass了,太烂大街了。不知道动态线程池能不能做。反正项目上新有风险,不一定来得及,非必要就不开新的项目。补充:别跟我扯RAG了,这玩意已经成新的烂大街了,详见我上一篇的吐槽。3.认真学微调prompt什么的这个半步踩进算法了已经。八股和场景题完全就是另一套,没两三个月搞不定的。约等于换方向
简历中的项目经历要怎么写
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务