蓝桥杯训练——Python的力扣困难题恢复数组

题目

  1. 恢复数组
  2. 某个程序本来应该输出一个整数数组。但是这个程序忘记输出空格了以致输出了一个数字字符串,我们所知道的信息只有:数组中所有整数都在 [1, k] 之间,且数组中的数字都没有前导 0 。

给你字符串 s 和整数 k 。可能会有多种不同的数组恢复结果。

按照上述程序,请你返回所有可能输出字符串 s 的数组方案数。

由于数组方案数可能会很大,请你返回它对 10^9 + 7 取余 后的结果。

示例 1:

输入:s = “1000”, k = 10000
输出:1
解释:唯一一种可能的数组方案是 [1000]
示例 2:

输入:s = “1000”, k = 10
输出:0
解释:不存在任何数组方案满足所有整数都 >= 1 且 <= 10 同时输出结果为 s 。
示例 3:

输入:s = “1317”, k = 2000
输出:8
解释:可行的数组方案为 [1317],[131,7],[13,17],[1,317],[13,1,7],[1,31,7],[1,3,17],[1,3,1,7]
示例 4:

输入:s = “2020”, k = 30
输出:1
解释:唯一可能的数组方案是 [20,20] 。 [2020] 不是可行的数组方案,原因是 2020 > 30 。 [2,020] 也不是可行的数组方案,因为 020 含有前导 0 。
示例 5:

输入:s = “1234567890”, k = 90
输出:34

解析

分三个方面分析
一、先考虑不含0,且k足够大的情况
s = “1317”, k = 2000 为例
字符串从1开始下标。
i = 0 时,对应s = ”“,可以解析成空数组 所以dp[0] = 1
i = 1 时,对应s = ”1“,只能解析成 [1], 所以 dp[1] = 1
i = 2 时,对应s = ”13“,只能解析成 [1, 3] 和 [13], 所以 dp[2] = 2
这里,”3“作为数字3加入时,2接在dp[1]构成的所有数组后面,对应的是dp[1], "3"作为数字13加入时,13接在dp[0]构成的所有数组后面,对应时dp[0],所以有转移方程 dp[2] = dp[1] + dp[0]
i = 3 时,对应s = ”131“,dp[3] = 4,dp[3] = dp[2] + dp[1] + dp[0]
i = 4 时,对应s = ”1317“,dp[4] = 8,dp[4] = dp[3] + dp[2] + dp[1] + dp[0]
二、考虑不含0,但是k有限的情况
s = “1317”, k = 20 为例
i = 0 时,对应s = ”“,可以解析成空数组 所以dp[0] = 1
i = 1 时,对应s = ”1“,只能解析成 [1], 所以 dp[1] = 1
i = 2 时,对应s = ”13“,只能解析成 [1, 3] 和 [13], 所以 dp[2] = dp[1] + dp[0] = 2
i = 3 时,对应s = ”131“,”3“只能作为数字3加入,所以dp[3] = dp[2] = 2
i = 4 时,对应s = ”1317“,dp[4] = 4,dp[4] = dp[3] + dp[2] = 4
三、考虑含0,但是k有限的情况
s = “1310”, k = 400 为例
i = 0 时,对应s = ”“,可以解析成空数组 所以dp[0] = 1
i = 1 时,对应s = ”1“,只能解析成 [1], 所以 dp[1] = 1
i = 2 时,对应s = ”13“,只能解析成 [1, 3] 和 [13], 所以 dp[2] = dp[1] + dp[0] = 2
i = 3 时,对应s = ”131“,”1“能作为数字1,31,131加入,所以dp[3] = dp[2] + dp[1] + dp[0] = 4
i = 4 时,对应s = ”1310“,”0“可以作为数字10加入,也可以作为数字310加入,所以dp[4] = dp[2] + dp[1] = 3

这是最复杂的一种情况,可以拆解开来看,
(1)首先,0不能构成数组,0只能与其前面的非0数字构成数字
if s[j] == “0”: continue
(2)0可以作为多少种数字加入,取决于其前面的非0数字大小,例如上面的10, 310.但是如果是”1510“,那就只能以10加入
(3)有一点优化,如果当前字符是0,且与前面的第一个非0字符构成的数字大于k,那么说明往后不能再构成数字了,直接返回0
if s[i - 1] == “0” and dp[i] == 0: return 0

代码

class Solution:
def numberOfArrays(self, s: str, k: int) -> int:
n=len(s)
dp=[0]*(n+1)
dp[0]=1
mod=1000000007

    for i in range(1,n+1):
        for j in range(i-1,-1,-1):
            if s[j]=='0':
                continue
            if int(s[j:i])<=k:
                dp[i]+=dp[j]
            else:
                if s[i-1]=='0' and dp[i]==0:
                    return 0
                break
        dp[i]%=mod
    return dp[-1]%mod

运行结果

在这里插入图片描述

声明

解析是借鉴大佬的,这只是练习使用,不做商业用途

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值