MOD = 10**9 + 7
class Solution:
def numberOfArrays(self, s: str, k: int) -> int:
n = len(s)
dp = [0] * (n + 1)
dp[n] = 1 # Base case: empty string has 1 way
for i in range(n - 1, -1, -1):
if s[i] == '0':
continue # Numbers can't have leading zeros
num = 0
for j in range(i, n):
num = num * 10 + int(s[j])
if num > k:
break
dp[i] = (dp[i] + dp[j + 1]) % MOD
return dp[0]
class Solution {
public:
int numberOfArrays(string s, int k) {
const int MOD = 1e9 + 7;
int n = s.size();
vector<int> dp(n + 1, 0);
dp[n] = 1;
for (int i = n - 1; i >= 0; --i) {
if (s[i] == '0') continue;
long num = 0;
for (int j = i; j < n; ++j) {
num = num * 10 + (s[j] - '0');
if (num > k) break;
dp[i] = (dp[i] + dp[j + 1]) % MOD;
}
}
return dp[0];
}
};
class Solution {
public int numberOfArrays(String s, int k) {
int MOD = 1000000007;
int n = s.length();
int[] dp = new int[n + 1];
dp[n] = 1;
for (int i = n - 1; i >= 0; --i) {
if (s.charAt(i) == '0') continue;
long num = 0;
for (int j = i; j < n; ++j) {
num = num * 10 + (s.charAt(j) - '0');
if (num > k) break;
dp[i] = (dp[i] + dp[j + 1]) % MOD;
}
}
return dp[0];
}
}
var numberOfArrays = function(s, k) {
const MOD = 1e9 + 7;
const n = s.length;
const dp = new Array(n + 1).fill(0);
dp[n] = 1;
for (let i = n - 1; i >= 0; --i) {
if (s[i] === '0') continue;
let num = 0;
for (let j = i; j < n; ++j) {
num = num * 10 + Number(s[j]);
if (num > k) break;
dp[i] = (dp[i] + dp[j + 1]) % MOD;
}
}
return dp[0];
};
Given a string s
consisting of digits and an integer k
, you are asked to restore the array by splitting s
into a sequence of integers, where:
1
and k
(inclusive).s
into such a sequence. Since the answer can be large, return it modulo 10^9 + 7
.
Constraints:
1 <= s.length <= 10^5
1 <= k <= 10^9
s
does not contain leading zeros unless the number is zero itself.
The problem is about splitting a string of digits into valid numbers, making sure each is within a given range and does not have leading zeros. The naive way is to try every possible split, but with up to 10^5
digits, this would be far too slow.
Instead, we realize that for each position in the string, we can try forming numbers by taking one digit, two digits, and so on, until the number exceeds k
or we hit a leading zero. For each valid split, we recursively count the number of ways to split the remaining string. This is a classic case for dynamic programming (DP), where we cache the results for each starting position to avoid redundant work.
dp[i]
where dp[i]
represents the number of ways to split the substring starting at index i
.dp[n] = 1
, where n
is the length of s
. This means there's one way to split an empty string (do nothing).i
(from right to left), if s[i]
is not '0', try all possible splits by taking substrings s[i:j+1]
where the numeric value is ≤ k
. For each valid split, add dp[j+1]
to dp[i]
.s[i]
is '0', skip it because numbers cannot start with zero.dp[0]
gives the total number of ways to split the original string.dp
from the end because each state depends on future states (suffixes).
Example: Let s = "1234"
and k = 34
.
s[0] = '1'
):
Counting up the valid ways:
log10(k)
digits (since numbers must be ≤ k
).k
(at most 10 for k = 10^9
).
The problem is a classic example of using dynamic programming to count the number of ways to partition a string under constraints. The key insight is to process the string from the end, using a DP array to store the number of ways to split each suffix. By only considering valid splits (no leading zeros, number ≤ k
), and by leveraging the fact that large numbers of splits share subproblems, we achieve an efficient and elegant solution.