leetcode 1416. Restore The Array(恢复数组)

在这里插入图片描述

一台打印机没有把空格打印出来,以至于不知道打印出的 s 中到底有哪些数字。
现在知道数字的取值范围在1 ~ k, 数字开头不能是0.
返回可能的数字个数。取模109+7.

思路:

DP

假设dp[ i ]为 i ~ n位的s 所能组成的数字组合数。

从右到左遍历,说下为什么是从右到左。
因为数字要连续出现的,以“1317"为例,如果从左到右,比如现在遍历到 j = 2, 即第2个1,
而“131”这个数字中,如果取了“13”,那么和j=3的“7”组合时,就不连续了,变成了"13"和“7",这个是不好控制的。

下面以Example3的"1317"为例来说明。

初始状态,空字符串,个数为1,dp[4]=1,

i = 3, s[ i ] = “7”,7 < k, 7与空字符串组合,那么需要知道空字符串有多少种可能(dp[4] )。
这时dp[ 3 ] += dp [ 4 ].

i = 2, s[2] = “1”,1 < k,
“1”可与“7”组合成[1, 7],也可与空字符串组合成[1], 因此需要知道"7"有多少种可能( dp [ 3 ] ).
这时dp [ 2 ] += dp [ 3 ].

i = 1, s[ i ] = “3”, 3 < k, 可以选择"3"和“17”组合,那么需要知道“17”有多少种可能,
于是有[3, 17] 和 [3, 1, 7]
这时dp [ 1 ] += dp [ 2 ].

也可以选择“31“和”7“组合,31 < k, 那么需要知道"7"有多少种可能。
这时dp [ 1 ] += dp [ 3 ].

最后i = 0, s[0] = “1”, 1 < k, "1"可以和"317"组合,
dp[0] += dp[1]
13 < k , "13“和”17“组合,( [13, 17], [13, 1, 7], [13, 1] )
dp[0] += dp[2]
131 < k, "131"和“7”组合,( [131, 7] )
dp[0] += dp[3]

前提是当前数字 <= k, 如果当前数字 > k, 则进入下一个 i 的遍历。
如果当前s [ i ]为0,也进入下一遍历,因为数字不能是0开头。
最后返回dp[0], 即 0 ~ n-1的组合数。

    public int numberOfArrays(String s, int k) {
        final int MOD = (int)1e9+7;
        int n = s.length();
        int[] dp = new int[n+1]; //dp[i]:i~n的组合个数
        char[] chs = s.toCharArray();

        dp[n] = 1;
        for(int i = n-1; i >= 0; i--) {
            if(chs[i] == '0') continue; //0开头的不算
            long sum = 0, num = 0;
            for(int j = i; j < n; j++) {
                num = num*10 + (chs[j]-'0');
                if(num > k) break;
                sum += dp[j+1];
            }
            dp[i] = (int)(sum % MOD);
        }
        return dp[0];
    }

在这里插入图片描述

如果实在不好理解,可以参考下面的流程

初始状态,'': dp[4]=1
i=3,指向s[3]=7
j=3,指向s[3]=7
现在num=7
num (7) < k (2000)
[7 ~ 7] 和 [''] 组合
dp[3] += dp[4]=1
dp[3]=1

i=2,指向s[2]=1
j=2,指向s[2]=1
现在num=1
num (1) < k (2000)
[1 ~ 1] 和 [7~ 最后] 组合
dp[2] += dp[3]=1
j=3,指向s[3]=7
现在num=17
num (17) < k (2000)
[1 ~ 7] 和 [''] 组合
dp[2] += dp[4]=2
dp[2]=2

i=1,指向s[1]=3
j=1,指向s[1]=3
现在num=3
num (3) < k (2000)
[3 ~ 3] 和 [1~ 最后] 组合
dp[1] += dp[2]=2
j=2,指向s[2]=1
现在num=31
num (31) < k (2000)
[3 ~ 1] 和 [7~ 最后] 组合
dp[1] += dp[3]=3
j=3,指向s[3]=7
现在num=317
num (317) < k (2000)
[3 ~ 7] 和 [''] 组合
dp[1] += dp[4]=4
dp[1]=4

i=0,指向s[0]=1
j=0,指向s[0]=1
现在num=1
num (1) < k (2000)
[1 ~ 1] 和 [3~ 最后] 组合
dp[0] += dp[1]=4
j=1,指向s[1]=3
现在num=13
num (13) < k (2000)
[1 ~ 3] 和 [1~ 最后] 组合
dp[0] += dp[2]=6
j=2,指向s[2]=1
现在num=131
num (131) < k (2000)
[1 ~ 1] 和 [7~ 最后] 组合
dp[0] += dp[3]=7
j=3,指向s[3]=7
现在num=1317
num (1317) < k (2000)
[1 ~ 7] 和 [''] 组合
dp[0] += dp[4]=8
dp[0]=8

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值