-
题目:
输入一个int n,输出整数1~n的10进制表示中1出现的次数; -
思路:
1.逐位统计10进制下个位,十位,百位,。。。,最高位出现1的个数:时间O((log10 n) ^ 2):一个数字n共有log10 n位,每层循环内求l和r的操作也需要log10 n,因此共为(log10 n) ^ 2,空间为(log10 n),额外需要一个数组
class Solution {
public:
int countDigitOne(int n) {//例如:n=13015
if (!n) return 0;
vector<int> number;//把数字n转成大小位log10 n的数组处理
while (n) number.push_back(n % 10), n /= 10;//51031
reverse(number.begin(), number.end());//13015
int cnt = 0;
for (int i = 0; i < number.size(); ++i) {//例如i=2
int l = 0, r = 0, t = 1;//按i把数字n分成左半边数和右半边数, t是为了方便下面计算,实际就是10^(r的位数)
for (int j = 0; j < i; ++j) l = l * 10 + number[j];//l = 13
for (int j = i + 1; j < number.size(); ++j) r = r * 10 + number[j], t *= 10;//r = 15, t = 100
if (number[i] == 0) cnt += l * t;//l取[00, 12],r取[00, 99]
else if (number[i] == 1) cnt += l * t + r + 1;//l取[00,12],r取[000,99] 或 l==13,r取[00,15]
else cnt += (l + 1) * t;//l取[00,13],r取[00,99]
}
return cnt;
}
};
2.方法1的优化:时间为O(log10 n):随着cur的左移,l和r的随之改变,空间O(1):无需数组,改而维护cur,l,r
class Solution {
public:
int countDigitOne(int n) {//例如:n=13015
if (!n) return 0;
int res = 0, t = 1;//t表示cur的右边数r的位数
int cur = n % 10, l = n / 10, r = 0;//从个位开始,逐位统计
while (l || cur) {//若只写l,会漏掉cur取最高位的情况
if (cur == 0) res += l * t;//cur取百位0时,l取[00, 12], r取[00,99]
else if (cur == 1) res += l * t + r + 1;//cur取十位1时,l取[000, 129],r取[0,9] 或l取[130],r取[0,5]
else res += (l + 1) * t;//cur取千位3时,l取[0,1],r取[000,999]
r += cur * t;//r向左多一位
cur = l % 10;//cur左移一位
l /= 10; //l少一位
t *= 10;//t多乘个10
}
return res;
}
};