力扣 每日一题 902. 最大为 N 的数字组合难度:困难,rating: 1989(数学 / 数位dp)
Posted nefu-ljw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了力扣 每日一题 902. 最大为 N 的数字组合难度:困难,rating: 1989(数学 / 数位dp)相关的知识,希望对你有一定的参考价值。
题目链接
https://leetcode.cn/problems/numbers-at-most-n-given-digit-set/
题目来源于:第101场周赛 Q3 rating: 1989
思路一(数学)
设 n 的位数(长度)为 len_n,digits 的长度为 len_d,那么长度小于 len_n 的从 digits 中取出的所有任意组合均满足条件,方案数: ∑ i = 1 l e n _ n − 1 ( l e n _ d ) i \\sum_i=1^len\\_n-1 (len\\_d)^i ∑i=1len_n−1(len_d)i。
接着处理长度相等的组合情况。
- 依次找到 n 的每一位数字在 digits 数组中的大概位置 k ,比 k 小的所有 digits 数构成的任意组合均满足条件。
- 判断 digits 数组中位置 k 的数字与 n 的该位数字是否相等,如果相等则接着遍历 n 的下一位数字,继续比较;否则结束比较。
- 当遍历到 n 的最后一位数字时,比 k 小于等于的所有 digits 数均满足条件。
代码一
class Solution
int qpow[11]=0; // len_d^i
int base[11]=0; // len_d^1 + len_d^2 +...+ len_d^i
public:
int atMostNGivenDigitSet(vector<string>& digits, int n)
int len_d=digits.size();
base[0]=0;
qpow[0]=1;
for(int i=1;i<=9;i++)
qpow[i]=qpow[i-1]*len_d; // len_d^i
base[i]=base[i-1]+qpow[i]; // base[i]表示小于10^i的所有方案,即长度小于等于i的所有方案
vector<int> digits_int;
for(const string &s:digits)
digits_int.push_back(s[0]-'0');
string str_n=to_string(n);
int len_n=str_n.size();
int ans=base[len_n-1]; // 长度小于len_n的方案数
for(int i=0;i<len_n;)
char c=str_n[i];
int x=c-'0'; // x是n的第i位的数字
if(i!=len_n-1)
// k是digits中小于x的位数
int k=lower_bound(digits_int.begin(),digits_int.end(),x)-digits_int.begin();
ans+=k*qpow[len_n-i-1];
if(k!=len_d&&digits_int[k]==x) // 当前位置数字相等
i++; // 继续找下一位,继续比较
else
break; // 否则结束比较
else
// 到达最后一位
// k是digits中小于等于x的位数
int k=upper_bound(digits_int.begin(),digits_int.end(),x)-digits_int.begin();
ans+=k;
break;
return ans;
;
/*
["3","4","8"]
4
ans: 2
["5","7","8"]
59
ans: 6
["1","4","5","6","7","8"]
52
ans: 19
["1"]
834
ans: 3
*/
思路二(数位dp)
待补
代码二
以上是关于力扣 每日一题 902. 最大为 N 的数字组合难度:困难,rating: 1989(数学 / 数位dp)的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 0902. 最大为 N 的数字组合「抽象出了函数,看着较为明白的代码 + 手推」