题目
思路
我的思路是用数学方法解,首先把找出比n低位的数,比如n是500,就先找出1-99之间的数,假如digits中有3个数,此时能在1-99之间的数字组合个数就为 个,如果n是1000,能在1-999之间的数字组合就为个。设digit就是n的位数,公式就是
然后我们要找的就是与n同位的部分,比如
digits = ["1","3","4","6"]
n = 5000
因为5大于1、3、4,所以我们只用求到1、3、4这三个数开头且符合要求的四位数个数
再加上前面低位的个数就能得到答案。但假如n的开头在digits的数里面,且后面几位不为0,用上面的例子,把n改成6431,我们就要在6000-6431之间找到符合要求的数字组合。所用的方法和上面有些相似,因为4大于1、3,所以我们可以求以61、63开头的四位数个数
然后再推向下一位,因为3大于1,所以我们可以求以641开头的四位数个数
最后我们发现6431也符合要求,答案再加1。将这些可能全都加起来就是我们所需要的答案。再比如当n=6500时,我们需要找到6000-6500之间符合要求的数字组合,这其实等效于找出n=500时的答案,在这种情况下就不需要继续往下推了。
class Solution {
public:
int atMostNGivenDigitSet(vector<string>& digits, int n) {
int dn[10];
int digit = 0;
int tmpn = n;
while (tmpn > 0) {
dn[digit ++] = tmpn%10;
tmpn /= 10;
}
int ans = 0;
//找出比n低位的部分
for (int i = 1; i <= digit - 1; i ++) {
ans += pow(digits.size(),i);
}
//和n同位数的部分
for (int i = digit-1; i >= 0; i --) {
if(!dn[i]) break;
int index = 0;
while(dn[i] > ((int)digits[index][0] - '0')) {
index ++;
if (index >= digits.size()) break;
}
ans += index*pow(digits.size(), i);
if (index >= digits.size()) index--;
if(dn[i] != ((int)digits[index][0] - '0')) break;
if(!i&&dn[i] == ((int)digits[index][0] - '0')) ans ++;
}
return ans;
}
};
提交结果
总结
这题更像是一个数学题目,找到规律然后求解,这个方法的时间复杂度也很低。还可以使用动态规划的方法求解。