leetcode 第 298 场算法比赛/未参赛

作者: | 更新日期:

有事,便无法参加比赛了。

本文首发于公众号:天空的代码世界,微信号:tiankonguse

零、背景

这次比赛,由于我有事,所以就无法参加比赛了。

现在有时间了,做了下比赛,坑有不少。

一、兼具大小写的最好英文字母

题意:问哪个字母的大小写都出现了,求出现的字典树最大的那个字母。

方法1:边遍历边寻找。

维护一个集合,代表前面出现的字母。
边遍历,边判断大小写反转的字母是否存在集合,存在了就找到一个答案,再判断是否可以更新为最优值。
之后,再把当前字母加入到集合。

方法2:预处理集合,枚举答案。

遍历一遍字符串,将所有字符加入到集合里。
之后从后到前枚举每个字母,判断是否是答案。

二、个位数字为 K 的整数之和

题意:求最少的整数个数,要求这些整数各位都是 k,整数之和是 num。

方法1:动态规划

状态定义:f(n) 代表和为 n 的最少整数。

状态转移方程如下:

i % 10 == k;
f(n) = min(f(i) + 1)

复杂度:O(n^2)

方法2:贪心

分析9*9乘法表,只观察个位,可以发现,每个数字都有自己的循环节。

0 => 0
1 => 1,2,3,4,5,6,7,8,9,10
2 => 2,4,6,8,10
3 => 3,6,9,12,15,18,21,24,27,30
4 => 4,8,12,16,20
5 => 5,10
6 => 6,12,18,24,30
7 => 7,14,21,28,35,42,49,56,63,70
8 => 8,16,24,32,40
9 => 9,18,27,36,45,54,63,72,81,100

这意味着有两个推论。

瑞伦1:如果数字和在循环节之内,则可能有答案,否则没答案。

推论2:一个数字,是否存在答案,在循环节之内可以判断出来。

贪心思路:数字和不断的减去 k,循环节之内,剩余和个位可以等于 k,则答案是减去的次数加一。

例子:假设和为 182, k 为 4 第一次减法:182-4=178
第二次减法:178-4=174
故最小的整数集合为4,4,174
答案为 3.

三、小于等于 K 的最长二进制子序列

题意:给一个二进制字符串,求最长的子序列,使得子序列的值不大于 K。

方法1:贪心

贪心之前需要想到两个推论。

推论1:选择 0 比选择 1 更优。
推论2:选择低位的 1 比选择高位的 1 更优。

有了这两个推论,我们就可以预处理计算出 0 的个数,然后从后到前求后缀的值 ,来看是否可以得到更优答案。
一旦无法得到更优答案,遍历就结束。

方法2:动态规划

假设:我们可以储存下字符串对应的十进制

状态定义:f(n, i) 前 n 个字符里面选 i 个字符可以得到最小十进制。

状态转移方程:

f(n, i) = min(f(n-1, i), f(n-1,j-1)*2 + v)  

解释:分为选择当前字符与不选择。
选择了就是之前的最优值左移加上当前的值。

问题:字符串长度上千位,必然会越界。

绝妙之处:状态转移方程修改为下面的样子

f(n, i) = min(f(n-1, i), f(n-1,j-1)*2 + v)  
f(n, i) = min(f(n, i), k+1)

解释:既然目标是求不大于 k 的数字,大于 K 的统一标记为 k+1 即可。

四、卖木头块

题目:给一个大矩阵,以及一些小矩阵的长、宽、价值。
大矩阵需要切割为与小矩阵匹配的大小才能得到对应的价值。
但是,切割的时候只能横着一刀切或者竖着一刀切。
小矩阵的个数都是无限的,问怎么切割才能得到最大价值。

思路:如果思考的顺序不对,这道题可能就做不出来了。

起初,我思考的是先选择小矩阵,然后决定横着切一刀或者竖着切一刀,结果发现复杂度很高。

后来,我逆向思考,枚举横竖的所有切割,再求出不切割的最优价值,取最大值即可

不切割的最优价值,其实就是求二维最优值,好像需要树套树,我也不会。

后来,我突然意识到,不切割的最优值,在枚举横竖切的时候,也会遇到。
所以,不切割只需要判断是否存在当前不切割大小矩阵的输入矩阵即可。

算法:

预处理输入,储存在二维表格中,代表一个矩阵是否存在,存在了价值是多少。

状态:f(n,m)大小为 n*m的矩阵可以得到的最大价值。

状态转移方程:

f(n, m) = input(n, m) // 不存在为0
f(n, m) = max(f(n, m), f(i, m) + f(n-i, m))
f(n, m) = max(f(n, m), f(n, i) + f(n, m-i))

复杂度:O(n*3)

五、最后

这次比赛除了最后一题,前三题都有三种方法,我都第一时间想到的是方法一。

其中第三题的方法二非常妙,是一个不错的思路,值得学习

而对于第四题,则不好评价。

如果从枚举小矩阵入手,可能就会陷入无底深渊。
如果从枚举切割入手,就会想二维线段树,进而发现预处理打标记即可。

总的来说,我认为这次比赛算比较难吧。

不过由于我没参加比赛,就知道我能排多少名了。

加油,算法人。

《完》

-EOF-

本文公众号:天空的代码世界
个人微信号:tiankonguse
公众号ID:tiankonguse-code

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

关注公众号,接收最新消息

tiankonguse +
穿越