たとえば、一連の数値の各数値の桁数の積を計算しようとしています。
21, 22, 23 ... 98, 99 ..
だろう:
2, 4, 6 ... 72, 81 ..
複雑さを軽減するために、 from toや from toなど、限られた長さの数字の [連続した数字]のみを検討します。001
999
0001
9999
ただし、数列が大きい場合、たとえば のように、数字を1000000000
繰り返し抽出してからすべての数に対して乗算するのは非効率的です。
基本的な考え方は、計算中に遭遇する連続するゼロをスキップすることです。たとえば、次のようになります。
using System.Collections.Generic;
using System.Linq;
using System;
// note the digit product is not given with the iteration
// we would need to provide a delegate for the calculation
public static partial class NumericExtensions {
public static void NumberIteration(
this int value, Action<int, int[]> delg, int radix=10) {
var digits=DigitIterator(value, radix).ToArray();
var last=digits.Length-1;
var emptyArray=new int[] { };
var pow=(Func<int, int, int>)((x, y) => (int)Math.Pow(x, 1+y));
var weights=Enumerable.Repeat(radix, last-1).Select(pow).ToArray();
for(int complement=radix-1, i=value, j=i; i>0; i-=1)
if(i>j)
delg(i, emptyArray);
else if(0==digits[0]) {
delg(i, emptyArray);
var k=0;
for(; k<last&&0==digits[k]; k+=1)
;
var y=(digits[k]-=1);
if(last==k||0!=y) {
if(0==y) { // implied last==k
digits=new int[last];
last-=1;
}
for(; k-->0; digits[k]=complement)
;
}
else {
j=i-weights[k-1];
}
}
else {
// receives digits of a number which doesn't contain zeros
delg(i, digits);
digits[0]-=1;
}
delg(0, emptyArray);
}
static IEnumerable<int> DigitIterator(int value, int radix) {
if(-2<radix&&radix<2)
radix=radix<0?-2:2;
for(int remainder; 0!=value; ) {
value=Math.DivRem(value, radix, out remainder);
yield return remainder;
}
}
}
これは数値の列挙のみを目的としており、ゼロを含む数値が最初に計算されるのを避けるために、数字の積はまだコードによって与えられていません。ただし、計算を実行するデリゲートを提供して数字の積を生成するには、まだ時間がかかります。
連続した数字の桁積を効率的に計算するには?