How to find all taxicab numbers less than N?

前端 未结 8 1515
攒了一身酷
攒了一身酷 2021-01-30 14:11

A taxicab number is an integer that can be expressed as the sum of two cubes of integers in two different ways: a^3+b^3 = c^3+d^3. Design an algorithm to find all t

8条回答
  •  别那么骄傲
    2021-01-30 14:48

    It seems like a simple brute-force algorithm with proper bounds solves it in time proportional to n^1.33 and space proportional to n. Or could anyone point me to the place where I'm mistaken?

    Consider 4 nested loops, each running from 1 to cubic root of n. Using these loops we can go over all possible combinations of 4 values and find the pairs forming taxicab numbers. It means each loop takes time proportional to cubic root of n, or n^(1/3). Multiply this value 4 times and get:

    (n^(1/3)^4 = n^(4/3) = n^1.33
    

    I wrote a solution in JavaScript and benchmarked it, and it seems to be working. One caveat is that the result is only partially sorted.

    Here is my JavaScript code (it's not optimal yet, could be optimized even more):

    function taxicab(n) {
      let a = 1, b = 1, c = 1, d = 1,
      cubeA = a**3 + b**3,
      cubeB = c**3 + d**3,
      results = [];
    
      while (cubeA < n) { // loop over a
        while (cubeA < n) { // loop over b
          // avoid running nested loops if this number is already in results
          if (results.indexOf(cubeA) === -1) {
           while (cubeB <= cubeA) { // loop over c
            while (cubeB <= cubeA) { // loop over d
              if (cubeB === cubeA && a!=c && a!=d) { // found a taxicab number!
                results.push(cubeA);
              }
              d++;
              cubeB = c**3 + d**3;
            } // end loop over d
            c++;
            d = c;
            cubeB = c**3 + d**3;
           } // end loop over c
          }
          b++;
          cubeA = a**3 + b**3;
          c = d = 1;
          cubeB = c**3 + d**3;
        } // end loop over d
        a++;
        b = a;
        cubeA = a**3 + b**3;
      } // end loop over a
    
      return results;
    }
    

    Running taxicab(1E8) takes around 30 seconds in a browser console and yields 485 numbers as a result. Ten times smaller value taxicab(1E7) (10 millions) takes almost 1.4 seconds and yields 150 numbers. 10^1.33 * 1.4 = 29.9, i.e. multiplying n by 10 leads to the running time increased by 10^1.33 times. The result array is unsorted, but after quickly sorting it we get correct result, as it seems:

    [1729, 4104, 13832, 20683, 32832, 39312, 40033, 46683, 64232, 65728,
    110656, 110808, 134379, 149389, 165464, 171288, 195841, 216027, 216125,
    262656, 314496, 320264, 327763, 373464, 402597, 439101, 443889, 513000, 
    513856, 515375, 525824, 558441, 593047, 684019, 704977, 805688, 842751, 
    885248, 886464, 920673, 955016, 984067, 994688, 1009736, 1016496, 1061424,
    1073375, 1075032, 1080891, 1092728, 1195112, 1260441, 1323712, 1331064,
    1370304, 1407672, 1533357, 1566728, 1609272, 1728216, 1729000, 1734264,
    1774656, 1845649, 2048391, 2101248, 2301299, 2418271, 2515968, 2562112,
    2585375, 2622104, 2691451, 2864288, 2987712, 2991816, 3220776, 3242197,
    3375001, 3375008, 3511872, 3512808, 3551112, 3587409, 3628233, 3798613,
    3813992, 4033503, 4104000, 4110848, 4123000, 4174281, 4206592, 4342914,
    4467528, 4505949, 4511808, 4607064, 4624776, 4673088, …]
    

    Here is a code for benchmarking:

    // run taxicab(n) for k trials and return the average running time
    function benchmark(n, k) {
      let t = 0;
      k = k || 1; // how many times to repeat the trial to get an averaged result
    
      for(let i = 0; i < k; i++) {
        let t1 = new Date();
        taxicab(n);
        let t2 = new Date();
        t += t2 - t1;
      }
      return Math.round(t/k);
    }
    

    Finally, I tested it:

    let T = benchmark(1E7, 3); // 1376 - running time for n = 10 million
    let T2 = benchmark(2E7, 3);// 4821 - running time for n = 20 million
    let powerLaw = Math.log2(T2/T); // 1.3206693816701993
    

    So it means time is proportional to n^1.32 in this test. Repeating this many times with different values always yields around the same result: from 1.3 to 1.4.

提交回复
热议问题