Leetcode 每日一题和每日一题的下一题刷题笔记 9/30

282 阅读5分钟

Leetcode 每日一题和每日一题的下一题刷题笔记 9/30

写在前面

这是我参与更文挑战的第9天,活动详情查看:更文挑战

快要毕业了,才发现自己被面试里的算法题吊起来锤。没办法只能以零基础的身份和同窗们共同加入了力扣刷题大军。我的同学们都非常厉害,他们平时只是谦虚,口头上说着自己不会,而我是真的不会。。。乘掘金鼓励新人每天写博客,我也凑个热闹,记录一下每天刷的前两道题,这两道题我精做。我打算每天刷五道题,其他的题目嘛,也只能强行背套路了,就不发在博客里了。

本人真的只是一个菜鸡,解题思路什么的就不要从我这里参考了,编码习惯也需要改进,各位如果想找刷题高手请教问题我觉得去找 宫水三叶的刷题日记 这位大佬比较好。我在把题目做出来之前尽量不去看题解,以免和大佬的内容撞车。

另外我也希望有得闲的大佬提供一些更高明的解题思路给我,欢迎讨论哈!

好了废话不多说开始第九天的前两道题吧!

2021.6.9 每日一题

879. 盈利计划

这个题就很像运筹学里面那些题目的描述了,工厂里不同工种,不同原料,干活耗原料耗人力拿钱,这个题的条件还简单一些。

这个题可以看出有容量有价值,那这又是一道背包问题了。

价值就是盈利计划的总数目,容量是人数 n 和最小利润 minProfit。通常认为的容量是一个上限,但是背包问题的“容量”只是“限制”的具体化,限制本身有下限有上限两种。

还是直接采用空间复杂度优化的思路走,里层循环是逆序,倒着来。按正常顺序到最后会转移到 dp[n][minProfit] 这个状态上,这就是最终的答案(没有取模的结果)。然后一步一步往前,最前面的那种状态就是看到当前工作,从最开始的工作到当前工作参与的最大总人数,从最开始的工作到当前工作带来的最小总利润,从最开始的工作到当前工作产生的全部盈利计划总数。所以可以整理一下状态转移方程的定义了,dp[j][k] 的意思是在最多 j 人参与的情况下,已经开展的众多工作至少产生 k 的总利润的情况下,产生的盈利计划总数目。仔细看这里的说明,我把 i 空出来了,是因为之后还会用到 i,也就是已经开展的工作数量。这和前两天不太一样,前两天是因为最外层循环有些值取不到,不是逐个遍历,所以把 i 这个用到后面的变量上,不把 i 空出来也没问题。

下面讨论一下状态转移的过程。状态转移变量 jk 在一个状态里也只是两个范围,所以还需要两个变量把确实使用到的人数和确实获得的总利润表示一下。因为要转移,根据经验,这两个确实使用的值和当前这个工作有关系。当前这个工作确实使用到的人数和确实获得的总利润对应一种盈利计划,在这种盈利计划已经出现的情况下,要将前面所有工作除了当前这个工作,前面所有工作最大参与人数减去当前工作使用的人数,前面所有工作获得的最小总利润刨除当前工作的利润,这样的情况下获得的盈利计划数算出来,这样就有转移了。当然转移时找盈利计划总数目可不止这部分,还有一部分盈利计划是在前面所有工作中跳过了当前工作,其他工作在人数上限不变利润下限不变的情况下产生的盈利计划数。当然,假如一开始就没想着要进行当前这项工作,那上限下限都不变,和当前工作前一个工作那里得到的盈利计划数一样。整理一下,写出来就是

dp[j][k]={dp[j][k],not pick cur_workdp[j][k]+dp[jpeoplecur_work][kprofitcur_work],pick cur_weight\texttt{dp}[\texttt{j}][\texttt{k}] = {\left \{ \begin{array}{ll} \texttt{dp}[\texttt{j}][\texttt{k}], & not \ pick \ \texttt{cur\_work} \\ \texttt{dp}[\texttt{j}][\texttt{k}] + \texttt{dp}[\texttt{j} - \texttt{people}_\texttt{cur\_work}][\texttt{k} - \texttt{profit}_\texttt{cur\_work}], & pick \ \texttt{cur\_weight} \end{array} \right.}

这个状态转移方程里面的 cur_work 其实就是当前工作 i,在这里用上了,所以这个下标前面说要空出来。这样可以把状态转移方程进一步写成

dp[j][k]={dp[j][k],not pick idp[j][k]+dp[jpeople[i]][kprofit[i]],pick i\texttt{dp}[\texttt{j}][\texttt{k}] = {\left \{ \begin{array}{ll} \texttt{dp}[\texttt{j}][\texttt{k}], & not \ pick \ \texttt{i} \\ \texttt{dp}[\texttt{j}][\texttt{k}] + \texttt{dp}[\texttt{j} - \texttt{people}[\texttt{i}]][\texttt{k} - \texttt{profit}[\texttt{i}]], & pick \ \texttt{i} \end{array} \right.}

后面查错看题解才发现这里状态转移方程还是有点小问题。。。正确的状态转移方程里确定利润下限时要确保自己找的确实是有意义的下限。。。所以应该是 dp[j - people[i]][max(0, k - profit[i])] 这里确实一开始没想到。

代码和题解中给出的很像,就不拿过来献丑了。

image.png

2021.6.9 每日一题下面的题

1508. 子数组和排序后的区间和

这道题跟着思路一步一步写出来就行,排序那里可以优化,我这样的懒人就直接 sort。代码用题解的代码就可以。

image.png

小结

背包问题中状态转移方程里面的变量是可以填容量的,然后需要把确实使用的变量再表示出来,最好是最外层循环的函数,这样就构造出了一个不好用语言描述的状态转移。

参考链接