问题描述
我们有一组排序的数字 D,它是 {‘1’,‘2’,‘3’,‘4’,‘5’,‘6’,‘7’,‘8’,‘9’} 的非空子集。(请注意,‘0’ 不包括在内。)
现在,我们用这些数字进行组合写数字,想用多少次就用多少次。例如 D = {‘1’,‘3’,‘5’},我们可以写出像 ‘13’, ‘551’, ‘1351315’ 这样的数字。
返回可以用 D 中的数字写出的小于或等于 N 的正整数的数目。
示例 1:
输入:D = [“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.
解题报告
待完善
实现代码
- 我的代码,浅度剪枝【TLE】
深度有限搜索【TLE】
class Solution {
public:
int atMostNGivenDigitSet(vector<string>& D, int N) {
int ans=0,tmpN=N,nbit=0;
while(tmpN){
tmpN/=10;
nbit++;
ans+=pow(D.size(), nbit);
}
ans-=pow(D.size(),nbit);
DFS(ans, D, N, 0, 0, nbit);
return ans;
}
void DFS(int &ans, vector<string>& D, int N, int index, long sum, int nbit){
if(index==nbit)ans++;
else{
for(int i=0;i<D.size();i++){
if(sum*10+atoi(D[i].c_str())<=N)
DFS(ans, D, N, index+1, sum*10+atoi(D[i].c_str()), nbit);
else
return ;
}
}
}
};
- 别人的代码,深度剪枝
class Solution {
public:
int res=0,f=0;
int jisuan(int m,int n){
if(m==0) return 0;
int sum=0,x=1;
while(m){
x=x*n;
sum+=x;
m--;
}
return sum;
}
int dfs(vector<string>& D,string s,int pos){
if(pos==s.size()) return 1;//递归到了最后,表示每一位都是确定的,这也是一个答案,和N相等,所以返回1
int i;
for(i=D.size()-1;i>=0;i--){
if(s[pos]>=D[i][0]){
break;//找到D中大于等于当前位的
}
}
if(i>=0){
if(s[pos]>D[i][0]) return (i+1)*pow(D.size(),s.size()-pos-1);//不存在和当前位相等的,则不需要继续往下,后面的位取D中所有的数
else if(s[pos]==D[i][0]) return i*pow(D.size(),s.size()-pos-1)+dfs(D,s,pos+1);//存在和当前位相等的,先计算D中有几个比当前位小的,计算出符合条件的数,再需要继续往下
}
return 0;//D中的数都比当前位大,则不需要再往下
}
int atMostNGivenDigitSet(vector<string>& D, int N) {
string s=to_string(N);
res+=jisuan(s.size()-1,D.size());
// cout<<res<<endl;
res+=dfs(D,s,0);
return res;
}
};
参考资料
[1] Leetcode 902.最大为N的数字组合
[2] 世界哪有真情