编程之美 - 1 的数目
来源:互联网 发布:java main spring 编辑:程序博客网 时间:2024/06/05 14:57
问题:
给定一个十进制整数N,写下从1开始到N的所有数字,然后数一下其中1的个数。
例如N = 16,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
其中 1 的个数为 9 个。
分析:
第一种方式比较暴力, 一个数字一个数字的查。复杂度为 N*(log2N)
第二种方式找规律,如例子中N=16的情况来看:
- 第一个是个位上的 1: 1, 11 两个
- 第二个是十位上的 1: 10, 11, 12,13,14,15,16 七个
1: 9 个
再如N = 23
- 第一个是个位上的 1: 1, 11,21 三个
- 第二个是十位上的 1: 10 ~ 19 十个
1: 13 个所以如果 十位上递增了一个,那么个位上的1便会多加一个; 十位数决定个位数
如果十位上的数是一个1,或大于1,那么个位数有多少个,便决定十位上1的个数。
再如 N = 123
- 第一个是个位上的 1: 1, 11,21...121 0, 10 ,20, .... 120 13个
- 第二个是十位上的 1: 10 ~ 19, 110 ~ 119 20个
- 第三个是百位上的 1: 100 ~ 123, 24个1:13 + 20 + 24= 57
按照位数分析,每位上的1和它的高位和低位都有关系。 假设当前位 : c 高位: h 低位的数值: l step:10的进步
if (c == 1) // 1 的个数和高位和低位都有关系
cnt += h*(step/10) + l + 1
else if (c == 0) // 1 的个数和高位有关系
cnt += h*(step/10)
else // 当前位大于 1 的情况,和高位有关系
cnt += (h+1)*(step/10) +1
实例程序
#include <iostream>using namespace std;int calc(int N){ int nCnt = 0; int nH=0, nC=0, nL=0; int nStep = 10; cout << "N=" << N << endl << endl; while(nStep/10 <= N) { nC = (N % nStep)/(nStep/10); nH = N / nStep; nL = (N % nStep) - nC * (nStep/10); cout << "C=" << nC << " H=" << nH << " L=" << nL << " Step=" << nStep/10 << endl; switch(nC) { case 0: nCnt += nH*(nStep/10); break; case 1: nCnt += nH*(nStep/10) + nL+1; break; default: nCnt += (nH+1)*(nStep/10); break; } nStep *= 10; } cout << "count=" << nCnt << endl; cout << "=====================================\n" <<endl; return nCnt;}int main(){ int nRet = 0, i = 0; int test[] = {19,0,1,10,23,123,223,1023}; int len = sizeof(test)/sizeof(test[0]); for (i = 0; i < len; i++) { nRet = calc(test[i]); } cin >> nRet; return 0;}
扩展问题
二进制数,有下面的规律
f(1) = 1 (1有一个 1)
f(10) = 10 (01, 10 有2个 1)
f(11) = 100 (01 10 11 有4个 1)
函数f()的作用就是求二进制数中有多少个 1存在。
扩展问题分析
可以先从全 1 的情况开始分析:
f(1) = 1 (有1位 k = 1)
f(11) = 4 (有2位 k = 2)
f(111) = 12 (有3位 k = 3)
所以可以得到全 1 时的公式 k * 2^(k-1) k是一共有多少位数
那么一个二进制数 1 的个数可以拆成两个部分,去掉最高位 1 以后,剩下(k-1)位的全1的个数 + 加上最高位的1后的剩余个数
例如:
10010 就可以分成两个部分 1111 的1的和 + 从10000 到 10010 的1的和
从10000 到 10010 还可以继续拆分:
- 10010 最高位的1的个数是由后面的低位决定的 比如10010--> 10000, 10001,10010 红色的部分有三个。
- 0010 低位还需要继续按照上面的规则迭代,直到结束 0001 00010 两个 同 f(10)
扩展问题代码:
#include <iostream>using namespace std;/* first calculate the count of 1 in a full 1 number eg: 1 => cnt = 1; 11 => (01 10 11) cnt = 4; 111 => (001 010 011 100 101 110 111) cnt = 12 so we got cnt = k * 2^(k-1)*/int calc(char* binary, int len){ int nCnt = 1, num = 0; int k = len, total = 0; char* p = binary+1; if (len <= 0) return 0; while (k > 1) { if (binary[k-1]=='1') num += nCnt; nCnt *= 2; k--; } if (num == (nCnt-1)) // full of 1 return total = len*nCnt; else total = (len-1)*(nCnt/2); total += num+1; k = 1; while ((*p != '1') && (k<len)) { *p++; k++; } total += calc(p, len-k); return total;}int main(){ char* test[]= {"100", "1", "10", "11", "111", "10000", "1111", "10110", "110011", "110011001"}; int test_num = 10; int len = 0, i = 0, total=0; for (i = 0; i < test_num; i++) { len = strlen(test[i]); total = calc(test[i], len); cout << test[i] << ": result=" << total << endl; cout << "\n\n =========================\n" << endl; } cin >> len; return 0;}
1 0
- 编程之美之1的数目
- 编程之美之1的数目
- 编程之美---求1的数目
- 编程之美 2.4 “1”的数目
- 编程之美--1的数目
- 编程之美 2.4 1的数目
- 编程之美 1的数目
- 编程之美 1的数目【转】
- 编程之美 2.4 “1”的数目
- 【编程之美】1的数目
- 编程之美2.4 1的数目
- 编程之美-2.4 1的数目
- [编程之美2.4]1的数目
- 编程之美 2.4 1的数目
- 编程之美 1的数目
- 编程之美2.4 1的数目
- 编程之美:1的数目
- 编程之美-1的数目
- JDK各个版本的新特性jdk1.5-jdk8
- 代码优化:将重复代码封装成函数(3)
- 刚学的网页换肤
- python subprocess
- 多功能Label
- 编程之美 - 1 的数目
- Python2.6.6安装配置ICE3.4.2开发环境
- 如何坚持每周写一篇博客
- 【CodeForces】[658A]Bear and Reverse Radewoosh
- LIS最长上升子序列O(n^2)&O(nlogn)
- OC 中的 block
- MapReduce总结 (1)
- iOS——UINavigationController简单实用以及内存警告处理过程
- 七月算法机器学习笔记9 推荐系统