• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            雁過無痕

              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::

             《編程之美》讀書筆記21: 2.4 1的數目

             

            問題:

                給定一個十進制正整數N,寫下從1開始,到N的所有整數,

                然后數一下其中出現的所有“1”的個數。

                例如:

                  N=2,寫下 12。這樣只出現了 1 個“1”。

            N=12,我們會寫下 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12。這樣 1 的個數是 5

             

                1. 寫一個函數f(N),返回1N之間出現的“1”的個數,比如f(12)=5

            2. 32位整數范圍內,滿足條件“f(N)= N”的最大的N是多少?

             

                曾在ChinaUnix論壇上看到該題,記得是google的面試題,有個網友給出了不錯的解法,但他給出的證明倒是有點復雜,一直記不住。今天,無意間翻到這題,就順便再解了下。

             

            對問題一,可以采用書上的方法,分別對每個位進行統計。

             

            對問題二,可以證明N的上限值是10^10-1,不過就是采用10^11-1,對后面采用的算法影響也不大(只是多循環了300多次)。

             

            假設: a < c <bc = f(c)

            由函數f的定義可知:f(a) <= f(c) <= f(b)

            即: f(a) <= c <= f(b)

            又由 a< c < b可得 a + 1 <= c <= b-1

            因而  max(a+1, f(a))  <= c <= min(b-1, f(b))              ①

             

            假設 c含有k個數字,由于a每增加1f(a)最多增加k

            則有: f(c)  <= f(a) + (c - a) * k

                 f(c) = c > c – 1 可得  c – 1 < f(a) + (c - a) * k

            即: c > (a*k – f(a) - 1) / (k - 1) = a + (a – f(a) - 1) / (k - 1)

            即: c >= a + (a – f(a) - 1) / (k - 1) + 1    ( k > = 2)         

            當取等號時,c = a + (a – f(a) - 1) / (k - 1) + 1 <= a + (a – f(a) - 1) / 1 + 1 = a + (a – f(a))

            因而c的位數k小等于a + (a – f(a))的位數。

             

            假設b含有t個數字:

            同理可得 f(b) – 1 < f(b) <= f(c) + (b - c) * t = c + (b - c) * t 可得

            c < (b * t – f(b) + 1) / (t - 1) = b - (f(b) - b - 1) / (t - 1)

            即:c <= b - (f(b) – b - 1) / (t - 1) – 1     (t >= 2)            

             

            利用①、②、③這三個公式,可以去除不必要的計算。

            由公式①  max(a+1, f(a))  <=  c

            和公式②  c >= a + (a – f(a) - 1) / (k - 1) + 1

            可知:當計算了f(a)后,

            a > f(a) 下一個要計算的是: a + (a – f(a) - 1) / (k - 1) + 1

            a < f(a) 下一個要計算的是: f(a)

            1算到10^10-1,大概調用函數f四千多次,即可得到結果。

             

            可以只利用公式①來計算。

            max(a+1, f(a))  <= c <= min(b-1, f(b))

            將要計算的范圍劃分為幾個區間,然后對每個區間進行計算。比如說:

            1999,先將這些數劃分為10個區間:1-99100-199 … 900-999

            f(999) = 300可知,300以后的區間段可以不計算。當計算200時,可以先計算299,由于f(299)=160<200200-299的區間可以都不必計算。對要計算的區間,再將它劃分為10個區間,重復進行。這樣劃分的另一個好處是利用公式:f(10^n-1) n * 10^(n-1),保存上次算得的f(n)直接計算下個數的f(n)

             

            還可以利用公式②、③倒著計算:即從10^10-1開始算起。

             

            最高效的作法,可能是:先倒著計算,直到出現f(n) > n,然后再設計個算法劃分區間,從區間前計算。交替進行。但前面的幾種算法,效率都比較高,具體優化,效果并不明顯。

             

            下面的代碼的算法采用倒著算,計算N=f(N)

             

            初始值

            求N最大值,調用f函數次數

            求所有N值,調用f函數次數

            10^10-1

            604

            3164

            10^11-1

            979

            3539

             

            附:上限值證明:

            假設n=ak*10k+ ak-1*10k-1+…+ a1*101+ a0*100 ( ak-1, ak-2 … a0>=0; ak>=1)

                 非最高位中1出現的個數:

            當最高位從0ak-1,其它k位數出現的1個數:先從k位中取一位為1,剩余的k-1位組成共可組成k*10k-1個數,所以,1的個數總共為:ak*k*10k-1

            最高位為ak時,去除最高位后,剩余的數為n-ak*10k,其中1出現的個數為f(n-ak*10k)

            ② 最高位出現1的個數:

            如果ak>11出現的個數肯定大于ak=11出現的個數,

            ak=1時 最高位1出現的個數為:n-ak*10k+1

            (若ak>1  1出現的個數為 10k

            所以 f(n)>= ak*k*10k-1 + n-ak*10k+1 + f(n-ak*10k) > ak*(k/10 -1)* 10k-1 + n

            只要 k>=10, 就有 f(n)>n

            因此上限為 1010 – 1


            #include<iostream>
            using std::cout;

            inline unsigned count_digits(unsigned 
            long long num)
            {
              unsigned 
            long long n = 1;
              unsigned ret 
            = 0;
              
            while (n <= num) { n *= 10++ret; }
              
            return ret;
            }


            unsigned 
            long long count_ones(unsigned long long num)
            {
              unsigned 
            long long count = 0, factor = 1;
              unsigned 
            long long low = 0, cur;
              
            while (num != 0{
                cur 
            = num % 10;
                num 
            /= 10;
                unsigned 
            long long tmp = 0;
                
            if (cur > 1) tmp = factor; 
                
            else if (cur == 1) tmp = low + 1
                count 
            += num * factor + tmp;
                low 
            += factor * cur;
                factor 
            *= 10;
              }

              
            return count;
            }


            void get_nums()
            {
              unsigned 
            long long x = 1e11 - 1, y;
              unsigned count 
            = 0;
              unsigned idx 
            = 0;
              
            while (true{
                
            ++count;
                y 
            = count_ones(x);
                
            if (x < y) {
                  
            //x在1到10時,均不滿足x<y,所以x>10,下面的k值肯定大于0    
                  unsigned k = count_digits(x) - 1;
                  x 
            -= (y - x - 1)/+ 1
                }

                
            else if (x > y) { x = y; } 
                
            else {
                  cout
            << ++idx << "" << x << " " << count << "\n";
                  
            //break;
                  --x;
                  
            if (x == 0break;
                }
             
              }

            }


            int main()
            {
              get_nums();
            }


            posted on 2010-07-21 00:25 flyinghearts 閱讀(1065) 評論(0)  編輯 收藏 引用 所屬分類: 算法編程之美C++
            久久99精品国产99久久6| 久久久久亚洲精品无码蜜桃| 国产午夜久久影院| 嫩草影院久久国产精品| 欧美精品丝袜久久久中文字幕| 一级做a爰片久久毛片看看| 亚洲国产精品无码久久一区二区 | 久久精品国产男包| 国内精品伊人久久久影院| AV狠狠色丁香婷婷综合久久| 久久国产精品偷99| 久久久久亚洲av无码专区喷水| 麻豆精品久久精品色综合| 18禁黄久久久AAA片| 麻豆精品久久精品色综合| 中文字幕乱码久久午夜| 久久涩综合| 99久久99久久精品国产| 午夜天堂av天堂久久久| 久久中文精品无码中文字幕| 国产精品久久久久影视不卡| 久久久久久久女国产乱让韩| 精品久久久久久无码免费| 久久精品国产免费| 精品久久久久中文字幕日本| 国产精品久久久久免费a∨| 久久本道久久综合伊人| 久久精品国产免费| 99久久成人国产精品免费| 久久久这里有精品| 奇米影视7777久久精品人人爽| 久久久久久噜噜精品免费直播| 26uuu久久五月天| 亚洲精品高清久久| 国产精品99久久精品| 国产精品美女久久久久久2018| 亚洲AV日韩AV天堂久久| 久久综合精品国产二区无码| 久久久久久久久久久久久久| 97久久国产综合精品女不卡 | 久久久WWW成人免费毛片|