LeetCode.2999. 统计强大整数的数目
统计强大整数的数目
- 题目
- 整体思路
- Code
- 代码详细解释
- `calculate` 函数
- `numberOfPowerfulInt` 函数
- 复杂度分析
题目
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]
内满足条件的整数数量。
Code
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 是输入的整数。