持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
【LetMeFly】902.最大为 N 的数字组合「抽象出了函数,看着较为明白的代码 + 手推」
力扣题目链接:leetcode.cn/problems/nu…
给定一个按 非递减顺序 排列的数字数组 digits 。你可以用任意次数 digits[i] 来写的数字。例如,如果 digits = ['1','3','5'],我们可以写数字,如 '13', '551', 和 '1351315'。
返回 可以生成的小于或等于给定整数 n 的正整数的个数 。
示例 1:
输入:digits = ["1","3","5","7"], n = 100 输出:20 解释: 可写出的 20 个数字是: 1, 3, 5, 7, 11, 13, 15, 17, 31, 33, 35, 37, 51, 53, 55, 57, 71, 73, 75, 77.
示例 2:
输入:digits = ["1","4","9"], n = 1000000000 输出:29523 解释: 我们可以写 3 个一位数字,9 个两位数字,27 个三位数字, 81 个四位数字,243 个五位数字,729 个六位数字, 2187 个七位数字,6561 个八位数字和 19683 个九位数字。 总共,可以使用D中的数字写出 29523 个整数。
示例 3:
输入:digits = ["7"], n = 8 输出:1
提示:
1 <= digits.length <= 9digits[i].length == 1digits[i]是从'1'到'9'的数digits中的所有值都 不同digits按 非递减顺序 排列1 <= n <= 109
方法一:排列组合 + 动态规划
有两种数字小于:
- 数字位数直接小于的
- 数字位数和相同,但仍然小于
长度短的数字
对于第一种情况,假设,那么所有的三位数都小于
假设候选数字(有个),那么:
- 个位数有个
- 两位数有个
- 三位数有个
所有的三位数有个
长度和相等的数字
假设,
怎么计算长度为的数字中,小于的有多少个呢?
这里可以借助动态规划的思想,用两个变量和,分别代表遍历到的某一位(记为)时,“小于”和“等于”前位的位数的个数。
说人话就是:假如当前遍历到了的第位(第一个数是,第二个数是)
那么就是小于的两位数,就是等于的两位数。
最终遍历完的每一位后,即为小于等于的三位数
- 首先看的前位:
- 小于的位数有一个(),因此
- 等于的位数有一个(),因此
- 接着看的前位:
- 小于的位数有个(,小于的包括
第一位就小于6,这一位任意和第一位等于6,这一位必须小于3,而小于的数有个),因此 - 等于的位数有个(,等于的方案数为),因此
- 小于的位数有个(,小于的包括
- 最后看的前位:
- 小于的位数有个(,而小于的数有个),因此
- 等于的位数有个(),因此
因此小于等于的三位数有个
(加上一位数个和两位数个,由[2, 6, 7]组成的小于等于的数一共有个)
- 时间复杂度。前面求“短数字”的时间复杂度是,后面求“等长数字”的时间复杂度是(这里题目中说是升序的,因此还可以实用二分查找,但是数据量不大,因此不是很有必要)
- 空间复杂度
AC代码
C++
class Solution {
private:
/* 字符c是否在digits中 */
bool isIn(char c, vector<string>& digits) {
for (string& s : digits) {
if (c == s[0])
return true;
}
return false;
}
/* digits中小于字符c的元素的个数 */
int cntLessThan(char c, vector<string>& digits) {
int ans = 0;
for (string& s : digits) {
if (s[0] < c)
ans++;
}
return ans;
}
public:
int atMostNGivenDigitSet(vector<string>& digits, int n) {
int ans = 0;
// 求“短数字”
int len = to_string(n).size();
for (int i = 1; i < len; i++) {
ans += pow(digits.size(), i);
}
// 求“等长数字”
string strify = to_string(n);
int lessThan = cntLessThan(strify[0], digits), equal = isIn(strify[0], digits); // 实用常数空间
for (int i = 1; i < len; i++) {
lessThan = lessThan * digits.size() + equal * cntLessThan(strify[i], digits); // 公式原理在“631”的举例中详细说明了
equal = equal * isIn(strify[i], digits);
}
ans += lessThan + equal;
return ans;
}
};
同步发文于CSDN,原创不易,转载请附上原文链接哦~ Tisfy:letmefly.blog.csdn.net/article/det…