2

A large number can be comma formatted to read more easily into groups of three. E.g. 1050 = 1,050 and 10200 = 10,200.

The sum of each of these groups of three would be:

1050=1,050 gives: 1+50=51

10200=10,200 gives: 10+200=210

I need to search for matches in the sum of the groups of threes. Namely, if I am searching for 1234, then I am looking for numbers whose sum of threes = 1234.

The smallest match is 235,999 since 235+999=1234. No other integer less than 235,999 gives a sum of threes equal to 1234.

The next smallest match is 236,998 since 236+998=1234. One can add 999 each time, but this fails after reaching 999 since an extra digit of 1 is added to the number due to overflow in the 999.

More generally, I am asking for the solutions (smallest to highest) to:

a+b+c+d… = x

where a,b,c,d… is an arbitrary number of integers between 0-999 and x is a fixed integer

Note there are infinite solutions to this for any positive integer x.

How would one get the solutions to this beginning with the smallest number solutions (for y number of solutions where y can be an arbitrarily large number)?

Is there a way to do this without brute force looping one by one? I'm dealing with potentially very large numbers, which could take years to loop through in a straight loop. Ideally, one should do this without failed attempts.

user813801
  • 521
  • 2
  • 6
  • 23
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/204269/discussion-on-question-by-user813801-find-groups-of-thousands-which-sum-to-a-giv). – Samuel Liew Dec 14 '19 at 21:11

1 Answers1

2

The problem is easier to think about if instead of groups of 3 digits, you just consider 1 digit at a time.

An algorithm:

  • Start by filling the 0 digit group with x.

  • Create a loop that each time prints the next solution.

    • "Normalize" the groups by moving all that is too large from the right to the left, leaving only the maximum value at the right.
    • Output the solution
    • Repeat:
      • Add 1 to the penultimate group
      • This can carry to the left if a group gets too large (e.g.999+1 is too large)
      • Check whether the result didn't get too large (a[0] should be able to absorb what was added)
      • If the result got too large, set the group to zero and continue incrementing the earlier groups
    • Calculate the last group to absorb the surplus (can be positive or negative)

Some Python code for illustration:

x = 1234
grouping = 3
max_iterations = 200
max_in_group = 10**grouping - 1

a = [x]

while max_iterations > 0:
    #step 1: while a[0] is too large: redistribute to the left
    i = 0
    while a[i] > max_in_group:
        if i == len(a) - 1:
            a.append(0)
        a[i + 1] += a[i] - max_in_group
        a[i] = max_in_group
        i += 1

    num = sum(10**(grouping*i) * a[i] for i, n in enumerate(a))
    print(f"{num}  {num:,}")
    # print("".join([str(t) for t in a[::-1]]), ",".join([str(t) for t in a[::-1]]))

    # step 2:  add one to the penultimate group, while group already full: set to 0 and increment the
    #   group left of it;
    #   while the surplus is too large (because a[0] is too small) repeat the incrementing
    i0 = 1
    surplus = 0
    while True:  # needs to be executed at least once, and repeated if the surplus became too large
        i = i0
        while True:  # increment a[i] by 1, which can carry to the left
            if i == len(a):
                a.append(1)
                surplus += 1
                break
            else:
                if a[i] == max_in_group:
                    a[i] = 0
                    surplus -= max_in_group
                    i += 1
                else:
                    a[i] += 1
                    surplus += 1
                    break
        if a[0] >= surplus:
            break
        else:
            surplus -= a[i0]
            a[i0] = 0
            i0 += 1

    #step 3: a[0] should absorb the surplus created in step 1, although a[0] can get out of bounds
    a[0] -= surplus
    surplus = 0
    max_iterations -= 1

Abbreviated output:

235,999 236,998 ... 998,236 999,235 ... 1,234,999 1,235,998 ... 1,998,235 1,999,234 2,233,999 2,234,998 ... 

Output for grouping=3 and x=3456:

459,999,999,999 460,998,999,999 460,999,998,999 460,999,999,998 461,997,999,999
461,998,998,999 461,998,999,998 461,999,997,999 461,999,998,998 461,999,999,997
462,996,999,999 ...

Output for grouping=1 and x=16:

79 88 97 169 178 187 196 259 268 277 286 295 349 358 367 376 385 394 439 448 457 466
475 484 493 529 538 547 556 565 574 583 592 619 628 637 646 655 664 673 682 691 709
718 727 736 745 754 763 772 781 790 808 817 826 835 844 853 862 871 880 907 916 925
934 943 952 961 970 1069 1078 1087 1096 1159 1168 1177 1186 1195 1249 1258 1267 1276
1285 1294 1339 1348 1357 1366 1375 1384 1393 1429 1438 1447 1456 1465 1474 1483 1492
1519 1528 1537 1546 1555 1564 1573 1582 1591 1609 1618 1627 1636 1645 1654 1663 1672
1681 1690 1708 1717 1726 1735 1744 1753 1762 1771 1780 1807 1816 1825 1834 1843 1852
1861 1870 1906 1915 1924 1933 1942 1951 1960 2059 2068 2077 2086 2095 2149 2158 2167
2176 2185 2194 2239 2248 2257 2266 2275 2284 2293 2329 2338 2347 2356 2365 2374 2383
2392 2419 2428 2437 2446 2455 2464 2473 2482 2491 2509 2518 2527 2536 2545 2554 2563
2572 2581 2590 2608 2617 2626 2635 2644 2653 2662 2671 2680 2707 2716 2725 2734 ...
JohanC
  • 71,591
  • 8
  • 33
  • 66
  • testing this. does it skip any possible solutions before going to bigger number solutions? thanks – user813801 Dec 14 '19 at 19:40
  • I think the algorithm quite efficiently finds the next solution based on the current solution. Usually only the buckets 0 and 1 need to be inspected. I didn't do a full complexity analysis, but I suspect it is about as fast as it can get. – JohanC Dec 14 '19 at 21:21
  • checking some more to make sure not missing any solutions. – user813801 Dec 14 '19 at 21:37
  • Yes, please tell me if you'ld encounter a missing solution. I did quite some testing and everything looks OK. It also works efficiently for very large numbers. – JohanC Dec 14 '19 at 21:41
  • follow up question to this answer https://stackoverflow.com/questions/59346503/ – user813801 Dec 15 '19 at 21:21
  • running this: at index 204000... a print() of variable a gives:[503, 505, 654, 984, 55] dump:20400000000-55984654505503 while for index 208000.... a print() of a gives: [843, 888, 843, 70, 57] dump:20800000000-5770843888843 i.e. the solution 57708... is smaller than 5598...is this a bug? maybe the 70 should be 070? – user813801 Dec 16 '19 at 13:54
  • Yes, the printing in groups of 3 doesn't add the zeros. To improve it, one has to print the first group without padding, and the next groups with zero-padding. An easier fix is to multiply each group with the correct power of 10, then sum, and depend on Python's big integers. – JohanC Dec 16 '19 at 14:03
  • The new version of the code does the zero padding using Python's big integers. – JohanC Dec 16 '19 at 14:14
  • great. will test it out. does this mean i have to restart the whole program from zero to get the right index? – user813801 Dec 16 '19 at 14:32
  • If the number you're searching for doesn't need leading zeros, there isn't a problem. It depends on how you compare the strings. All internal values are correct, it is only the display that was wrong. If you printed out the counter and the content of the number string, you can also restart with those values. – JohanC Dec 16 '19 at 14:53
  • trying it on 5 digit numbers such as 12345 seems to be hanging. – user813801 Jan 14 '20 at 20:43
  • A copy paste of this code and changing 1234 to 12345 runs just fine. Note that the smallest number that sums to 12345 is 39 digits long. So, if you want the millionth number that can take a while. – JohanC Jan 14 '20 at 22:27