If you don't mind keeping the numbers in memory, you can encode the following algorithm:
- Start with numbers 0.1 ... base-1
- For each digit
d added, first add a zero, and then all previous numbers starting with digits d or higher (indexing by the starting digit and the number of digits, you can access them directly).
Or, like some kind of phrases, dp style: let dp[i][j] represent a sequence of numbers with i digits and the leftmost digit j . Then dp[i][j] = [d] ++ map (d +) dp[l][k], for all l < i and k >= j, where d = j * 10 ^ (i - 1)
(I borrowed ++ from Haskell, where it often means concat lists).
For example, base 4, 3 digits:
Start with one digit: 0,1,2,3 Add to the second digit from the first sequence: 10,11,12,13 20,22,23 30,33 Third digit, add from all previous sequences: 100,101,102,103 110,111,112,113 120,122,123 130,133 200,202,203 220,222,223 230,233 300,303 330,333
JavaScript Code:
var base = 4; var dp = [,[]]; for (var j=0; j<base; j++){ dp[1][j] = [j]; } for (var i=2; i<4; i++){ dp[i] = []; for (var j=1; j<base; j++){ var d = j * Math.pow(10,i - 1); dp[i][j] = [d]; for (var l=1; l<i; l++){ for (var k=j; k<base; k++){ dp[i][j] = dp[i][j].concat( dp[l][k].map(function(x){ return d + x; })); } } } } console.log(JSON.stringify(dp))