天高云淡,秋高气爽,又是一个金秋。
秋天是收获的时节,作者在今年的夏秋之际以一名计算机专业应届生的身份参加了秋招。当中经历了许多挫折和挑战,也收获了许多知识和感悟;对自己的当下有了更加深刻的认识,对未来的生活也有了一些计划。当然最重要的,收获了一份比较满意的互联网公司软件研发岗位的Offer,嘻嘻,要挣钱了。
秋风吹起,金色的落叶簌簌飘扬而下,反射着金色的阳光,真是金色的好时光啊。让我想起了两年前,也是这样的一个金色日子,那天是周末,我走在校园里,准备去做做LeetCode的代码题,一眨眼啊,时光就飞奔向前,把我带到了今天。
我的LeetCode之旅大约是在两年前的春天,在同实验室的一位学长的影响下开始的(这位学长给我许多有益的影响,是那种在身边,我又比较钦佩的人)。而写博文的习惯主要是从今年年初是养成的,目前为止博文记录的内容都是自己在完成代码题时遇到的一些较难的、较巧妙的、值得记录的题解。主要目的就是对它们进行一个记录,在写成文章这一过程中加深印象,同时也方便以后回顾;当然了,还有一个目的就是为了在秋招的过程中将它作为一个吸引面试官的加分点,嘿嘿。
我的博客应该确实在秋招中起到了一点作用,可能引起了一些面试官的兴趣。当然了,更重要的,它锻炼了我的总结能力,描述和表达能力,静下来写一段文字、做一些事的能力,还有坚持的能力。
当然了,现在我的博客内容还是比较单一,只有代码题解,这也反映出了个人的欠缺。当然并不是说我只会做代码题而不会其他和计算机软件开发相关的知识,只是自觉在其他方面知识的投入还不够,深度还不够,知识结构不够健全。因此在因为忙于秋招而停止更新博客一段时间后,我又回来啦!接下来我会继续写有关代码题题解的博文(比如今天这一篇,虽然还没开始正式内容。。。),还会更新一些有关Java软件开发相关技术栈的内容,包括Java网络编程、Java多线程、JVM等,后面可能还会有数据库和SSM、Spring-boot相关内容。这些都是在秋招中认识到的从事软件开发至关重要的知识——毕竟秋招虽然结束,但学习之路没有结束
好了,开始今天的内容吧
既然是秋天,那就来一场秋游,赏赏秋叶,看这道收藏秋叶的题吧
这里是题目描述LeetCode-LCP 19.秋叶收藏集
本题采用多重线性动态规划方法,就是多次迭代地使用线性动态规划,后一次迭代的动态规划操作以前一次或者前几次迭代动规操作的结果为依据。
具体到本题,我们有字符串leaves
表示落叶集,设字符串长度为n
且n>=3
。那么我们构建二维动规表int[][] dp=new int[3][n+1]
,第一维的3
表示需要三次迭代动规,第二维用于存储每次计算结果,长度设n+1
是为了方便计算
第一次迭代动规:dp[0][i]
存储子串leaves[0:i)
(注意区间的开闭)全是红叶这种情况需要的最少操作次数。当当前叶子leaves[i-1]
是红叶时,不需要调整操作,dp[0][i]=dp[0][i-1]
;当叶子是黄叶时,需要一个替换操作,因此dp[0][i]=dp[0][i-1]+1
第二次迭代动规:dp[1][i]
存储leaves[0:i)
先有红叶,然后有黄叶这种情况。这时,有前面的叶子全红和前面的叶子先红后黄两种情况进行选择。当前叶子是黄叶时,不用额外操作,dp[1][i]=min(dp[0][i-1],dp[1][i-1])
;当前叶子是红叶时,需要一次替换操作,dp[1][i]=min(dp[0][i-1],dp[1][i-1])+1
第三次迭代动规:dp[2][i]
存储leaves[0:i)
先有红叶,然后有黄叶,最后又变成红叶这种情况。这时,有前面的叶子前红后黄和前面的叶子先红后黄再红两种情况进行选择。当前叶子是红叶时,不用额外操作,dp[1][i]=min(dp[0][i-1],dp[1][i-1])
;当前叶子是黄叶时,需要一次替换操作,dp[1][i]=min(dp[0][i-1],dp[1][i-1])+1
最后dp[2][n]
就是所求的最少操作次数
需要注意的是,dp[0][0]=0
,dp[0]
从下标1
开始动规计算;dp[1][0]~dp[1][1]
和dp[0]
相等,dp[1]
从下标2
开始动规计算;dp[2][0]~dp[2][2]
和dp[1]
相等,dp[2]
从下标3
开始动规计算
以leaves="rrryyyrryyyrr"
为例,动规表如下:
题解代码:
public class Solution {
public static void main(String[] args) {
String leaves="rrryyyrryyyrr";
Solution obj=new Solution();
System.out.println(obj.minimumOperations(leaves));
}
public int minimumOperations(String leaves) {
int[][] dp=new int[3][leaves.length()+1]; //用于多重线性动规的动规表
//第一重动规,计算leaves[0,i)全红状态所需的最少修改次数
for(int i=1;i<=leaves.length();i++)
{
if(leaves.charAt(i-1)=='r')
{
dp[0][i]=dp[0][i-1];
}
else
{
dp[0][i]=dp[0][i-1]+1;
}
}
//第二重动规,计算leaves[0,i)先红再黄状态所需要的最少修改次数
for(int i=0;i<2;i++)
{
dp[1][i]=dp[0][i];
}
for(int i=2;i<=leaves.length();i++)
{
if(leaves.charAt(i-1)=='y')
{
dp[1][i]=Math.min(dp[0][i-1],dp[1][i-1]);
}
else
{
dp[1][i]=Math.min(dp[0][i-1],dp[1][i-1])+1;
}
}
//第三种动规,计算leaves[0,i)先红再黄然后又变红状态所需要的最少修改次数
for(int i=0;i<3;i++)
{
dp[2][i]=dp[1][i];
}
for(int i=3;i<=leaves.length();i++)
{
if(leaves.charAt(i-1)=='r')
{
dp[2][i]=Math.min(dp[1][i-1],dp[2][i-1]);
}
else
{
dp[2][i]=Math.min(dp[1][i-1],dp[2][i-1])+1;
}
}
return dp[2][leaves.length()];
}
}
时间复杂度:O(n)
空间复杂度:O(n)