生成一系列数字
要检查单个数字是否在某个基数中包含相等的相邻数字,请在下面进一步查看我的初始答案。如果要生成在某个基数中相邻数字不相等的数字范围,最好将检查构建到生成器中,而不是检查所有数字。
下面的代码示例创建一个特定基数中每个数字的值的表,并将数字零创建为一个数字数组。具有相同基数的每个后续调用都会增加数字,同时跳过相等的相邻数字。
function next(base, reset) {
// If this is the first call, or if the base has been changed, a
// new table with the values of digits in this base is generated.
if (base !== next.base) {
initialize_table();
reset = true;
}
// If reset flag is set, re-initialize array of digits to zeros.
if (reset) {
initialize_digits();
return 0;
}
increment_digits();
return calculate_value();
// The distinct parts of the algorithm have been split into
// seperate functions for clarity; for speed, integrate them.
function initialize_table() {
// The base, digit value table and array of digits are stored
// as static variables, to be re-used between function calls.
next.base = base;
next.table = [];
// Set a maximum for the values in the table (here it's 32-bit
// unsigned integers); this determines the size of the table.
// No overflow checking is done; add this if required.
for (var pos = 0, val = 1, step = 1; val < 4294967296; pos++){
next.table[pos] = [0];
for (var digit = 1; digit < base; digit++, val += step) {
next.table[pos][digit] = val;
}
step = val;
}
}
function initialize_digits() {
next.digit = [];
for (var pos = 0; pos < next.table.length; pos++) {
next.digit[pos] = 0;
}
}
function increment_digits() {
// Find the lowest digit that can be incremented.
// No overflow checking is done; add if required.
var pos = 0;
while (next.digit[pos] == base-1 ||
next.digit[pos] == base-2 &&
next.digit[pos+1] == base-1) {
++pos;
}
// Add 1, or 2 if adding 1 would equal the next digit.
while (++next.digit[pos] == next.digit[pos+1]);
// Set the lower digits to 0 or 1 alternatingly.
for (pos-- ; pos >= 0; pos--) {
next.digit[pos] = (next.digit[pos+1] == 0) ? 1 : 0;
}
}
function calculate_value() {
// Look up value for each digit in the table and add up.
var val = 0;
for (pos = 0; pos < next.digit.length; pos++) {
val += next.table[pos][next.digit[pos]];
}
return val;
}
}
for (var b = 9; b > 1; b--) {
document.write(b + " → ");
for (var i = 0; i < 25; i++)
document.write(next(b) + " ");
document.write("...<br>");
}
检查单个号码
最有效的方法(特别是如果您想检查具有相同基数的多个数字)是首先制作该基数中每个数字的值的表格,然后根据该数字从高到低检查数字.这样您就可以避免计算量很大的除法和模数,并且您可以在找到两个相同的数字后立即返回,而无需进行完整的基本转换。
假设基数为 6,数字为 16 位无符号整数,最大值为 65535,则表格为:
position: 0 1 2 3 4 5 6
digit:
0 -> 0 0 0 0 0 0 0
1 -> 1 6 36 216 1296 7776 46656
2 -> 2 12 72 432 2592 15552 -
3 -> 3 18 108 648 3888 23328 -
4 -> 4 24 144 864 5184 31104 -
5 -> 5 30 180 1080 6480 38880 -
假设我们正在检查数字 49876;我们首先检查第 6 位数字的值:
49876 >= 46656 ? yes
-> digit at position 6 is 1
然后我们从 49876 中减去 46656 得到 3220,然后继续检查第 5 位数字的值:
3220 >= 38880 ? no
3220 >= 31104 ? no
3220 >= 23328 ? no
3220 >= 15552 ? no
3220 >= 7776 ? no
-> digit at position 5 is 0
这个数字与前一个不同。我们从数字中减去任何内容,因为数字为零;然后我们转到位置 4 的数字值:
3220 >= 6480 ? no
3220 >= 5184 ? no
3220 >= 3888 ? no
3220 >= 2592 ? yes
-> digit at position 4 is 2
这个数字也和前一个不同。我们从 3220 中减去 2592 得到 628;然后我们转到位置 3 的数字值:
628 >= 1080 ? no
628 >= 864 ? no
628 >= 648 ? no
628 >= 432 ? yes
-> digit at position 3 is 2
这与前一个数字相同,因此我们知道该数字在基数 6 中具有两个相同的相邻数字。
该表可以仅使用加法构建,并且相对较小(最多 16×16 = 256 个元素,用于检查 base-16 中的 64 位整数),并且可以重复用于检查同一个中的多个数字根据。仅通过比较和减法来检查数字;绝对没有模数,除法甚至乘法,所以它应该非常快。
如果数字包含相同的相邻数字,则算法可以在检查所有数字之前返回答案。如果没有相同的相邻数字,则检查所有数字,这实际上是一个完整的基本转换;但至少它有效地完成了。