把数组排成最小的数
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
分析
这题肯定要使用排序,但是要怎么使用排序我想了好久都没有想明白,后来看了答案,才发现原来还可以这样排序。积累经验,代码倒是很简单,注意一下 sort 的用法就行了。
static bool cmp(int a, int b) {
string a1 = to_string(a);
string b1 = to_string(b);
return a1 + b1 < b1 + a1;
}
string PrintMinNumber(vector<int> numbers) {
sort(numbers.begin(), numbers.end(), cmp);
string ret = "";
for (vector<int>::iterator iter = numbers.begin(); iter != numbers.end(); ++iter) {
ret += to_string(*iter);
}
return ret;
}
整数中 1 出现的次数
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
分析
最简单的就是暴力解法。我知道这题肯定有简单的做法,但我想了好久还是没做出来,只好看别人的答案了。
先把暴力解法的代码贴上来吧。
int count_1(string n) {
int cnt = 0;
for (int i = 0; i < n.size(); ++i) {
if (n[i] == '1') {
++cnt;
}
}
return cnt;
}
// 学到了 to_string 这个函数
int NumberOf1Between1AndN_Solution(int n)
{
int cnt = 0;
for (int i = 1; i <= n; ++i) {
string str_i = to_string(i);
cnt += count_1(str_i);
}
return cnt;
}
另一种更快的方法:
先给出 1 的个数的计算公式:对于第 i 位(第一位:个位,第二位:十位)上的数字 X,将其与 数字 1 进行比较:
- X>1: (高位数字+1)*10^(i-1)
- X<1: (高位数字)*10^(i-1)
- x=1: (高位数字)*10^(i-1)+(低位数字+1)
(高位数字与低位数字:假设一个数字12345 ,对于七张的 3,高位数字为 12, 低位数字为 45)
然后给出一个共识:
10 里,1 作为个位出现了 1 次
100 里,1 作为 10 位出现了 10次
1000 里,1 作为百位出现了 100 次
以此类推:从 1到 (10^i)中,1 在对应位上出现 10^(i-1) 次
再用一个数字 3014 来举例说明:
分别看个、十、百、千上各有多少个 1
个位:有 301 个 10(每个 10 里有一个 1),再加上 3011里的个位 1,所以 个位中 1 的个数为 301+1=302。
对应公式:(301+1)*10^(1-1)=302
十位:有 30 个 100,十位数字为 1,个位为 4,有 5 个 1 (0~4),所以十位中有 30*10+5=305 个 1。
对应公式:30*10^(2-1)+4+1=305
百位:有 3 个 1000,则百位中 1 的个数为:3*10^(3-1)=300 个。
对应公式:3*10^(3-1)=300
千位:0 个 10000,没有更高位,1 作为 千位出现了 1000 次
对应公式:(0+1)*10^(4-1)=1000
最后把它们相加。
代码就偷个懒·不写了·。。。
参考文献
[1] 从1到n整数中1出现的次数
[2] 从1到n整数中1出现的次数