此题使用动态规划的方法。首先进行特殊情况的判断:如果字符串的第一个字符为'0',由于不能有前导0,直接返回0。定义dp数组f[i][j],表示考虑num的子串num[0..j],且最后一个数字为num[i..j]时的方案数。初始化f[0][i]=1,即当第一个数字扩展到i时,只有一种划分方案。对于每个位置i到j,若num[i]=='0',则跳过,因为不能有前导0。为了保证非递减,需要比较当前数字与前一个数字的大小。这通过预处理一个最长公共前缀数组lcp来辅助,减少比较次数。动态规划递推时,若当前数字大于等于前一个数字,则累加前面的方案数。最后,将所有以n-1结尾的方案数相加,得到总方案数。
时间复杂度: O(n^2)
空间复杂度: O(n^2)
class Solution:
def numberOfCombinations(self, num: str) -> int:
mod = 10**9 + 7
# 特殊情况处理,如果首字符为0,则无有效方案
if num[0] == '0':
return 0
n = len(num)
# 预处理最长公共前缀数组lcp
lcp = [[0] * n for _ in range(n)]
for i in range(n - 1, -1, -1):
lcp[i][n - 1] = int(num[i] == num[n - 1])
for j in range(i + 1, n - 1):
lcp[i][j] = (lcp[i + 1][j + 1] + 1 if num[i] == num[j] else 0)
# 初始化动态规划数组
f = [[0] * n for _ in range(n)]
for i in range(n):
f[0][i] = 1
for i in range(1, n):
if num[i] == '0':
continue
presum = 0
for j in range(i, n):
length = j - i + 1
f[i][j] = presum % mod
if i - length >= 0:
# 判断当前数字是否大于等于前一个数字
if lcp[i - length][i] >= length or num[i - length + lcp[i - length][i]] < num[i + lcp[i - length][i]]:
f[i][j] = (f[i][j] + f[i - length][i - 1]) % mod
presum += f[i - length][i - 1] if i - length >= 0 else 0
# 计算最终的方案数
ans = sum(f[i][n - 1] for i in range(n)) % mod
return ans