2999. 统计强大整数的数目
给你三个整数 start
,finish
和 limit
。同时给你一个下标从 0 开始的字符串 s
,表示一个 正 整数。
如果一个 正 整数 x
末尾部分是 s
(换句话说,s
是 x
的 后缀),且 x
中的每个数位至多是 limit
,那么我们称 x
是 强大的 。
请你返回区间 [start..finish]
内强大整数的 总数目 。
如果一个字符串 x
是 y
中某个下标开始(包括 0
),到下标为 y.length - 1
结束的子字符串,那么我们称 x
是 y
的一个后缀。比方说,25
是 5125
的一个后缀,但不是 512
的后缀。
示例 1:
输入:start = 1, finish = 6000, limit = 4, s = "124"
输出:5
解释:区间 [1..6000] 内的强大数字为 124 ,1124 ,2124 ,3124 和 4124 。这些整数的各个数位都 <= 4 且 "124" 是它们的后缀。注意 5124 不是强大整数,因为第一个数位 5 大于 4 。
这个区间内总共只有这 5 个强大整数。
示例 2:
输入:start = 15, finish = 215, limit = 6, s = "10"
输出:2
解释:区间 [15..215] 内的强大整数为 110 和 210 。这些整数的各个数位都 <= 6 且 "10" 是它们的后缀。
这个区间总共只有这 2 个强大整数。
示例 3:
输入:start = 1000, finish = 2000, limit = 4, s = "3000"
输出:0
解释:区间 [1000..2000] 内的整数都小于 3000 ,所以 "3000" 不可能是这个区间内任何整数的后缀。
代码通过两个主要函数 calculate
和 numberOfPowerfulInt
来完成计算。
calculate
函数:用于计算小于等于给定整数 x
且以字符串 s
为后缀,同时每个数位都不超过 limit
的整数的数量。numberOfPowerfulInt
函数:利用 calculate
函数,通过计算 finish
和 start - 1
对应的满足条件的整数数量,然后相减得到区间 [start, finish]
内满足条件的整数数量。long long calculate(const char* x, const char* s, int limit) {
int x_len = strlen(x);
int s_len = strlen(s);
if (x_len < s_len) {
return 0;
}
if (x_len == s_len) {
return strcmp(x, s) >= 0 ? 1 : 0;
}
char* suffix = (char*)malloc(s_len + 1);
strncpy(suffix, x + x_len - s_len, s_len);
suffix[s_len] = '\0';
long long count = 0;
int preLen = x_len - s_len;
for (int i = 0; i < preLen; i++) {
int digit = x[i] - '0';
if (limit < digit) {
count += (long long)pow(limit + 1, preLen - i);
free(suffix);
return count;
}
count += (long long)digit * (long long)pow(limit + 1, preLen - 1 - i);
}
if (strcmp(suffix, s) >= 0) {
count++;
}
free(suffix);
return count;
}
long long numberOfPowerfulInt(long long start, long long finish, int limit, const char* s) {
char start_[20], finish_[20];
sprintf(start_, "%lld", start - 1);
sprintf(finish_, "%lld", finish);
return calculate(finish_, s, limit) - calculate(start_, s, limit);
}
calculate
函数long long calculate(const char* x, const char* s, int limit) {
int x_len = strlen(x);
int s_len = strlen(s);
if (x_len < s_len) {
return 0;
}
if (x_len == s_len) {
return strcmp(x, s) >= 0 ? 1 : 0;
}
char* suffix = (char*)malloc(s_len + 1);
strncpy(suffix, x + x_len - s_len, s_len);
suffix[s_len] = '\0';
long long count = 0;
int preLen = x_len - s_len;
for (int i = 0; i < preLen; i++) {
int digit = x[i] - '0';
if (limit < digit) {
count += (long long)pow(limit + 1, preLen - i);
free(suffix);
return count;
}
count += (long long)digit * (long long)pow(limit + 1, preLen - 1 - i);
}
if (strcmp(suffix, s) >= 0) {
count++;
}
free(suffix);
return count;
}
参数说明:
x
:表示一个整数的字符串形式。s
:表示后缀字符串。limit
:表示每个数位的上限。逻辑步骤:
x
的长度小于 s
的长度,说明 x
不可能以 s
为后缀,直接返回 0。x
的长度等于 s
的长度,使用 strcmp
函数比较 x
和 s
,若 x
大于等于 s
,则返回 1,否则返回 0。suffix
用于存储 x
的后缀部分,长度为 s_len
。strncpy
函数复制 x
的后缀部分到 suffix
,并添加字符串结束符 '\0'
。preLen
表示 x
除去后缀部分的长度。x
的前缀部分,对于每个数位:
limit
,则计算剩余部分所有可能的组合数(每个数位可以取 0 到 limit
共 limit + 1
种值),并返回结果。suffix
大于等于 s
,则满足条件的整数数量加 1。suffix
分配的内存,并返回满足条件的整数数量。numberOfPowerfulInt
函数long long numberOfPowerfulInt(long long start, long long finish, int limit, const char* s) {
char start_[20], finish_[20];
sprintf(start_, "%lld", start - 1);
sprintf(finish_, "%lld", finish);
return calculate(finish_, s, limit) - calculate(start_, s, limit);
}
参数说明:
start
:区间的起始值。finish
:区间的结束值。limit
:每个数位的上限。s
:表示后缀字符串。逻辑步骤:
sprintf
函数将 start - 1
和 finish
转换为字符串形式,分别存储在 start_
和 finish_
中。calculate
函数分别计算小于等于 finish
和小于等于 start - 1
的满足条件的整数数量。[start, finish]
内满足条件的整数数量,并返回结果。calculate
函数的时间复杂度为 O ( l o g 10 x ) O(log_{10}x) O(log10x),其中 x x x 是输入的整数。numberOfPowerfulInt
函数调用两次 calculate
函数,因此总的时间复杂度也是 O ( l o g 10 f i n i s h ) O(log_{10}finish) O(log10finish)。calculate
函数中分配的 suffix
数组的空间,空间复杂度为 O ( l o g 10 x ) O(log_{10}x) O(log10x),其中 x x x 是输入的整数。