有这样一道题:1,2,3……n,这样写下去,求这一列数中,“1”出现的次数,记“1”的次数为f(n),求满足f(n)=n的最大的n。
看这题目有点像数论中的题目,学过数论的朋友一定会先在草稿纸上写
9 ----- 1
99 ----- 20
999 ----- 300
……
10^n-1 ----- n*10^(n-1) 式①
一下子就找到规律了,我最初也是这样列的式子,但在编程的时候却总感觉不好动手,于是我把这些排成一列
1
2
……
n
把数字对齐后,我很快发现,我只要将个位上的“1”,十位上的“1”……全部加起来,不就是题目的解么。而这也有规律,
个位上的“1” :每10个数就有一个“1”,不足10的时候,看其个位数是否大于等于1,代码表示为 n/10 + (n%10) > =1?1:0。
十位上的“1”:每100个数里面就有十个1,不足100的时候看其十位数是否大于1(取10)还是等于1(取个位数),还是小于1(取0),代码表示略
……
于是代码为:
ULONGLONG pw = 10;
m_nTimes = 0;// ”1“出现的次数
while(pw <= m_nNum)// m_nNum 为题目中的n
{
m_nTimes += (m_nNum/pw)*(pw/10);// 注意,不能化简为 m_nNum/10
if ((m_nNum%pw)/(pw/10) > m_nCnt)// m_nCnt ==1,还可以发散为m_nCnt 为两位数的情况
{
m_nTimes += pw/10;m_nTimes
}
else if ((m_nNum%pw)/(pw/10) == m_nCnt)
{
m_nTimes += m_nNum%(pw/10) + 1;
}
pw *= 10;
}
if (m_nNum/(pw/10) > m_nCnt)
{
m_nTimes += pw/10;
}
else if (m_nNum/(pw/10) == m_nCnt)
{
m_nTimes += m_nNum%(pw/10) + 1;
}
这个算法的时间复杂度为O(lg(n))
第二问
由式①可以看出,当n小于10的时候,总f(n)小于n,而n>11时,总有f(n)>n,暂时我也没有从数学上推出这个值,希望有推出的朋友告知一声
由于这个函数不递增函数,因此不能用二分方法来查找最大的n,听说答案是1 111 111 110,