问题描述
小U有一个特殊的“模板串”,这个串由数字字符和 '?' 组成。她可以通过将 '?' 替换成数字字符,来构造出多个正整数。不过有一个重要的限制条件:匹配出来的正整数不能有前导零。现在,小U想知道,按照字典序排列后,第 k 小的匹配数是多少?如果没有满足条件的第 k 小数,则返回 -1。
解题思路
通过分析题目,我们可以知道的是对于一个模板串,匹配出来的正整数不能有前导零。所以如果他的第一位是?,那么只能是从1开始,如果模板串本身就有前导零,那么就意味着直接没有满足条件的数,返回-1。而按字典序排序意味著符合数字的大小关系。那么我们只需要数数就可以了。我们将?提取出来,有几个?就是几位数,将其替换成可以有前导零的k-1,就可以了。当然,如果有?排在模板串的第一位,那么就应该以最大位为1其他为0开始计数,例如假设模板串有4个问号,那么应该从1000开始计数。
代码实现
首先是对模板串的第一位进行确认,如果是零,那么直接返回'-1',如果是'?',记录下标,并且值从1开始。
result = []
if s[0] == '0':
return '-1'
elif s[0] == '?':
result.append([0,'1'])
接着遍历模板串,将所有的'?'的位置记录,并从零开始计数。
for i, e in enumerate(s):
if i == 0:
continue
elif e == '?':
result.append([i, '0'])
检查数组中是否有值,如果没有那么模板串中没有'?'可用于替换,那么可以返回'-1'
if len(result) <= 0:
return '-1'
准备一个空串,将数组中的值提取出来转化成整型,好用于直接计数,然后计数就是了
num = ''
for i in result:
num += i[1]
num = str(int(num)+k-1)
再做一些判断即可,如果计数完成后,长度比数组长度长说明要计的数越界了,返回'-1'而如果记得数无法满足长度要求,那么我们需要将前导零补回去,因为之前将其转化成整型,有前导零的会被消除,其实主要是可能模板串的第一位是'?'导致可能不是从0开始,当然如果不想这样做,也可以在这一步判断一下是否模板串第一位是'?',然后对加上pow(10,len(result)-1),也是可以的,这表示最大位加一。然后将得到的数替换回去就可以了。
if len(num) > len(result):
return '-1'
while len(num) < len(result):
num = '0'+num
s = list(s)
for i in range(len(num)):
s[result[i][0]] = num[i]
当然因为我这里是替换,所以返回时就会使用list将原来的字符串转化成列表。又因为题目是要求返回的是完整字符串型,所以要做点处理。
return ''.join(s)
复杂度分析
时间复杂度
- 对于
s长度为n,我们首先遍历一次字符串s来找到'?'的位置,时间复杂度为 O(n) 。 - 然后,我们构造一个新的数字
num,这个过程的时间复杂度为 O(m) ,其中m是'?'的数量。 - 数字加法操作和字符串长度调整的时间复杂度也是 O(m)。
- 替换回原字符串的操作的时间复杂度是 O(m) 。
- 最后,转换列表为字符串的操作时间复杂度是 O(n) 。
因此,整体时间复杂度为 O(n + m) ,其中 n 是原字符串的长度,m 是字符串中 '?' 的个数。
空间复杂度
- 我们需要存储
result列表,存储替换字符的位置。空间复杂度为 O(m) ,其中m是'?'的个数。 - 另外,我们还需要存储数字字符串
num,其空间复杂度为 O(m) 。 - 最后,字符串转换成列表
s需要额外的空间,空间复杂度为 O(n) 。
因此,总的空间复杂度为 O(n + m) 。