update!
对于补充问题的想法其实来源于leetcode第286场周赛的第三题,要求求解指定长度的回文数。
当然,这道题本身的解法并不难,只需要从小到大枚举固定长度数的前半部分,然后做一下回文处理就可以了(实际上就是把前半部分复制到后面,注意奇数长度的话要吃掉一位)。贴一个该题的AC代码:虽然感觉写的非常的烂
1 | class Solution { |
但是我周赛的时候没想到,没想明白前半部分的大小就是回文数的大小。于是我有了一个非常奇怪的想法:二分搜索$[10^n,10^{n+1}-1]$,check$10^n$到$mid$范围内回文数的个数就行了。而统计一个范围内回文数的个数,属于数位dp解决问题的范畴。
但是问题来了,我并不知道如何用数位dp来求回文数。。。
经过简单的雾思考,有了一个数位dp来求解回文数问题的解法,顺便还找到了一道类似的问题:Problem
问题本身其实就是求回文数的个数,不过还需要求解在不同进制下的结果,转换下进制就好,问题主要还是如何求解回文数的个数。
先看段代码:
1 |
|
pos表示记录回文的其实位置,start表示当前的枚举数位,check表示判断结果,l表示进制数,其他的参数都是数位dp的常见参数。可以发现,前导零是一定会影响回文的判断的,所以当发现前导零时,pos-1,start-1继续搜;之后利用temp记录枚举的结果,当来到数的前半部分时,根据之前的判断结果和当前位是否符合回文规则即可,即$temp[pos-start+1]==i$。
之后提交,喜提Time Limit Exceeded。
经过了简单的挣扎,去看了其他大佬的解决方法,基本的框架都没有什么变化,只是前导零的判断条件变成了:
1 | if(i==0 && pos==start) |
减少了前导零标记lead,在同样解决问题的情况下,记录了更多的状态(之前lead==1时没记录的状态),从而减少了搜索所需的时间。
所以数位dp在解决问题的时候,在保证问题正确解决的前提下,还是需要尽可能的减少一些参数的使用,毕竟数位dp的时间复杂度实际上就是填满这些状态所需的时间。
最后附上完整的AC代码,虽然只是很小范围的改动:
1 |
|
end☆~