Counting of number 1 in a positive integer-Fast Calculation of F (N) (lower) using the divide and conquer method)

Source: Internet
Author: User

In my other article "counting of number 1 in a positive integer (I)", a simple algorithm is implemented to calculate F (n ). This algorithm is based on
Only the variation of two adjacent numbers is considered. Therefore, when calculating a single long integer (for example, n = 9111111110999009l), you can
It takes a long time to complete the calculation. Obviously, this algorithm has a narrow application scope. This article continues to discuss
A Quick Algorithm for calculating a single value of F (N) and how to obtain all integers that meet the value of f (I) = I (for a large number, the computing time can reach the order of milliseconds ).

Analysis:
First, we noticed that f (I), for example, to calculate I = 3260, actually repeats the previous computation when I = 3200.
Calculate the value from 1 to 60. This algorithm Splits a number into two halves Based on this consideration and adopts the divide-and-conquer method)
And then combine the two values. This is the same as merge sort.

First, the formula suitable for the partitioning algorithm is derived:
Take I = 3260 as an example. Split the number into the left half and right half, with 32 on the left and 60 on the right. You can find this equation:
F (3260) = f (3200) + [ones (32) * 60 + f (60)].
Here, ones (32) indicates the number of numbers 32 contain the number of numbers 1 (here it is equal to 0), ones (32) * 60 indicates 32 this number contains the number of numbers 1 need
Repeat 60 times (from 3201 ~ 3260), the value in the square brackets above is the total number of numbers 1 in the total number of 60 from 3201 to 3260.

Obviously, after this step, F (3260) is converted to a very small number F (60) and another very large number F (3200 ). Next
F (3200) performs similar processing:
F (3200) = ones (3200) + f (3199)
= Ones (32) + f (1, 3199)
= Ones (32) + [F (3100) + ones (31) * 99 + f (99)];... (equation 1)

F (3100) = ones (31) + f (3099)
= Ones (31) + [F (3000) + ones (30) * 99 + f (99)];... (equation 2)

......

F (200) = ones (2) + f (199)
= Ones (2) + [F (100) + ones (1) * 99 + f (99)];... (equation 31)

F (100) = ones (1) + f (99)
= Ones (1) + [F (99)]... (equation 32)

These equations replace each other (for example, replace F (3100) with the F (3100) value of the second formula to the right of the first formula). The final effect is
Accumulate, this is because F (3200) is not eliminated on the left, and other items are offset left and right) to get:
F (3200) = [ones (1) + ones (2) +... + ones (32)] + [ones (1) + ones (2) +... + ones (31)] * 99 + f (99) * 32
= F (31) * 100 + ones (32) + f (99) * 32;
Nice results! After a series of Complexity Reduction processing, F (3200) is converted to only two-digit values, that is, F (31) and F (99)
! Similarly, the equation of the original value F (3260) is:
F (3260) = f (31) * 100 + ones (32) * 61 + f (60) + f (99) * 32;
= Ones (32) * 61 + f (60) + f (31) * 100 + f (99) * 32;

Then, perform the same split calculation on the numbers F (31), F (60), and F (90) (the complexity is reduced by half !).

In general, for a relatively large number, such as N = 1234567890, split it into two halves, set the value on the left to leftnum, and the value on the right
The value is rightnum, and the number of digits corresponding to the right is rightcount. The total number of rightcount 9 is allrightnines, for example
There are five digits on the Right of 1234567890, so allrightnines = 99999. In this way, we can get:
F (n) = ones (leftnum) * (rightnum + 1) + f (rightnum)
+ F (leftNum-1) * (allrightnines + 1) + f (allrightnines) * leftnum;

 

Because the above equations of numbers such as F (9), F (99), F (999) Need
Therefore, these results are retained in the calculation process to facilitate sharing and achieve the effect of changing the time by space.

 

Update: All algorithms that meet f (I) = I are calculated based on the division and Control Method idea, similar to semi-query. Refer to solvebatch (...) in the following code (...). The basic principle is based on the fact that f (I) is an incremental sequence. If f (I) = J and j> I, then any number K (K! = J) cannot be equal to F (K), because F (k)> = f (I), that is, F (k)> = j> K. Therefore, you only need to consider whether the next number F (j) is equal to J. If f (I) = J and j <I, the situation is similar.

The following is the implementation code: In the Pentium M 1.4 GHz, 911111111099999009 M memory PC, the calculation F () =
1648888888779991781. It takes 911111111099999009 seconds to compute a number that meets the requirements of f (I) = I (I <= 0.221.

 

 

Import Java. util. arraylist; <br/> Import Java. util. collections; <br/> Import Java. util. list; <br/>/** <br/> * @ author lJS <br/> * 2011-05-23 <br/> */<br/> public class onescounter {<br/> // memoization: save the All nines F (N), like F (9), F (99), F (999 ).... <br/> private long [] allninesfn; <br/> private Boolean memoization; </P> <p> Public onescounter (Boolean memoization) {<br/> This. memoizatio N = memoization; </P> <p> If (memoization) {<br/> long max = long. max_value; </P> <p> int maxdigitscount = 1; <br/> while (max/= 10)> 0) <br/> maxdigitscount ++; <br/> allninesfn = new long [maxdigitscount + 1]; <br/>}< br/>/** <br/> * problem: <br/> * consider a function which, for a given whole number N, <br/> * returns the number of ones required when writing out all <br/> * numbers between 0 and N. <B R/> * For example, F (13) = 6. notice that F (1) = 1. <br/> * What is the next largest N such that F (n) = n? <Br/> * quick solution: using divide-and-conquer <br/> * return f (I) <br/> * n: long Integer <br/> */<br/> Public long quicksolve (long N) {<br/> // The number of digits in n <br/> int digitscount = 1; <br/> long TMP = N; <br/> while (TMP/= 10)> 0) <br/> digitscount ++; </P> <p> // separate N into digits <br/> byte [] digits = new byte [digitscount]; <br/> TMP = N; <br/> int P = digitscount-1; <br/> while (TMP> 0) {<br/> byte digit = (byte) (TMP % 10); <br/> digits [p --] = digit; <br/> TMP/= 10; <br/>}</P> <p> long result = quicksolve (digits ); </P> <p> // memoization feasibility check: All nines <br/> If (memoization & allninesfn [digitscount] = 0) {<br/> Boolean isallnines = true; <br/> for (INT I = 0; I <digitscount; I ++) {<br/> If (digits [I]! = 9) {<br/> isallnines = false; <br/> break; <br/>}< br/> If (isallnines) {<br/> // memoization <br/> allninesfn [digitscount] = result; <br/>}< br/> return result; <br/>}</P> <p> private long quicksolve (byte [] digits) {<br/> int digitscount = digits. length; </P> <p> If (digitscount = 1) {<br/> If (digits [0]> = 1) {<br/> return 1; <br/>}else {<br/> return 0; <br/>}</P> <p> int leftcount = digitscount/2; <br/> int rightcount = digitscount-leftcount; </P> <p> int leftones = 0; <br/> // count 1's in the left digits <br/> for (INT I = 0; I <leftcount; I ++) {<br/> If (digits [I] = 1) <br/> leftones ++; </P> <p >}</P> <p> long leftnum = digits [0]; <br/> // using Horner's rule <br/> for (INT I = 1; I <leftcount; I ++) {<br/> leftnum = leftnum * 10 + digits [I]; <br/>}</P> <p> int rightp = leftcount; // The start POS for the right half <br/> long rightnum = digits [rightp]; <br/> long allrightnines = 9; <br/> for (INT I = rightp + 1; I <digitscount; I ++) {<br/> rightnum = rightnum * 10 + digits [I]; <br/> allrightnines = allrightnines * 10 + 9; <br/>}</P> <p> long allrightninesresult = 0; <br/> // memoization usage <br/> If (memoization & allninesfn [rightcount]> 0) {<br/> allrightninesresult = allninesfn [rightcount]; <br/>} else {<br/> allrightninesresult = quicksolve (allrightnines); <br/>}</P> <p> long onescount = leftones * (rightnum + 1) <br/> + quicksolve (rightnum) + quicksolve (leftNum-1) * (allrightnines + 1) <br/> + allrightninesresult * leftnum; <br/> return onescount; <br/>}</P> <p> Public static list <long> foundlist = new arraylist <long> (); <br/> Public static void solvebatch (onescounter QC, long M, long n) {<br/> If (n <0 | n <m) return; </P> <p> long right = QC. quicksolve (n); </P> <p> If (n = m) {<br/> If (Right = N) {<br/> foundlist. add (n); <br/> // system. out. format ("F (% d) = % d % N", N, right); <br/>}< br/> return; <br/>}</P> <p> If (right <n) {<br/> solvebatch (QC, M, right ); <br/>} else if (Right = N) {<br/> foundlist. add (n); <br/> // system. out. format ("F (% d) = % d % N", N, right); <br/> solvebatch (QC, M, right-1 ); <br/>} else if (Right> N) {<br/> long midnum = (n + M)/2; <br/> long mid = QC. quicksolve (midnum); <br/> If (mid <midnum) {<br/> solvebatch (QC, M, mid); <br/> solvebatch (QC, midnum + 1, n-1); <br/>} else if (mid = midnum) {<br/> foundlist. add (midnum); <br/> // system. out. format ("F (% d) = % d % N", midnum, mid); <br/> solvebatch (QC, M, midNum-1 ); <br/> solvebatch (QC, midnum + 1, n-1); <br/>}else {<br/> solvebatch (QC, M, midNum-1 ); <br/> solvebatch (QC, mid, n-1 ); <br/>}</P> <p> Public static void main (string [] ARGs) {<br/> // long n = 1111111110; <br/> long n = 911111111099999009l; </P> <p> onescounter qc1 = new onescounter (true ); </P> <p> long start = system. currenttimemillis (); </P> <p> system. out. format ("Test 1: caculate F (% d) % N", n); </P> <p> long ones = qc1.quicksolve (n); <br/> system. out. format ("F (% d) = % d % N", N, ones); </P> <p> system. out. println (); <br/> system. out. format ("*********************** % N"); <br/> system. out. println (); </P> <p> system. out. format ("Test 2: caculate F (n) = n % N"); <br/> onescounter QC2 = new onescounter (true); <br/> onescounter. solvebatch (QC2, 0, n); <br/> system. out. format ("total numbers satisfying F (n) = n (n <% d): % d % N", N, foundlist. size (); <br/> collections. sort (foundlist); <br/> for (long K: foundlist) {<br/> system. out. format ("% d % N", k); <br/>}</P> <p> long end = system. currenttimemillis (); </P> <p> double timeelapsed = (end-Start)/1000.0; <br/> system. out. format ("time elapsed (SEC): %. 3f % N ", timeelapsed); </P> <p >}< br/>

Test results:

Test 1: caculate F (911111111099999009)
F (911111111099999009) = 1648888888779991781

**********************

Test 2: caculate F (n) = N
Total numbers satisfying F (n) = n (n <911111111099999009): 84
0
1
199981
199982
199983
199984
199985
199986
199987
199988
199989
199990
200000
200001
1599981
1599982
1599983
1599984
1599985
1599986
1599987
1599988
1599989
1599990
2600000
2600001
13199998
35000000
35000001
35199981
35199982
35199983
35199984
35199985
35199986
35199987
35199988
35199989
35199990
35200000
35200001
117463825
500000000
500000001
500199981
500199982
500199983
500199984
500199985
500199986
500199987
500199988
500199989
500199990
500200000
500200001
501599981
501599982
501599983
501599984
501599985
501599986
501599987
501599988
501599989
501599990
502600000
502600001
513199998
535000000
535000001
535199981
535199982
535199983
535199984
535199985
535199986
535199987
535199988
535199989
535199990
535200000
535200001
1111111110
Time elapsed (SEC): 0.220

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.