问题出在标题中。现在让自我产品这个词更加清晰。自我产品是指数字和数字的乘积。例如:
自我产品(1234)= 1234 * 1 * 2 * 3 * 4 = 29616。
我尝试了两种方法。
蛮力
任何人的想法都是检查1和N之间的所有组合(范围的上限)。并检查数字的自我产品是否在该范围内。这对于相对较低的数字来说是理想的,但是考虑到范围可能大到10 ^ 20,它会成为一个问题,因为它在打印结果之前需要一段时间。
分解
另一个想法是将范围内的数字分解。如果范围在60 000到70 000之间,当我检查62 688时,我将得到62 688为2 * 2 * 2 * 2 * 2 * 3 * 653。现在知道653不能成为一个数字,这意味着它必须是原始数字。然后我必须结合62 688的所有因素得到正确的答案,它应该输出这个是2612的自我产品,因为62 688 = 2612 * 2 * 6 * 1 * 2.
在这两种情况下,我都面临一个很大的问题,即检查所有组合。
P.S我发现如果数字有n位数,那么如果它的某个数字的自我产品比那个数字至少有n / 2位且不超过n。这将使我需要检查的数字列表略微缩小,但它并没有解决问题。
答案 0 :(得分:1)
<强>命名强>
sp(x) = Self-Product(x) = y
Range = a to b
备注:强>
我假设您只是想要计数,但是扩展它以实际打印所有数字应该不难。
基本思路 - 将x
拆分为具有某些数字前缀和一定数量的数字,然后确定某些数字+前缀是否完全在该范围内(添加可能性的数量) ,易于计算),部分(检查更长的前缀)或根本没有(沿着移动)。
请注意,不允许包含0的任何数字x
,因为y
= 0。
算法可能会有一些低效率,但它应该提供一个不错的起点。一个改进是应该能够进行一些二进制搜索过程。另一个不是一直重新计算最小值/最大值,因为这里有一定量的冗余。
<强>符号:强>
min(c,d)
- 最小为c位且前缀为d(min(c,)
表示无前缀)
max(c,d)
- 最多为c位且前缀为d
range(c,d)
- 范围从min(c,d)
到max(c,d)
请注意min(x,) = min(x,1) < min(x,2) < min(x,3) < ...
和
max(x,) = max(x,9) > max(x,8) > max(x,7) > ...
min(c,d..e)
- 带有c位的最小值集和从d到e的任何前缀
(min(c,d)
和min(c,e)
之间)
max(c,d..e)
- 带有c位的最大值集和从d到e的任何前缀
(在max(c,d)
和max(c,e)
之间)
算法通过示例:
我将使用Range = 100到200的示例进行解释。
// check 1 digit
min(1,): x = 1, y = 1*1 = 1 < 100
max(1,): x = 9, y = 9*9 = 81 < 100
// not in range, nothing to do
// check 2 digits
min(2,): x = 11, y = 11*1*1 = 11 < 100
max(2,): x = 99, y = 99*9*9 = 8019 > 200
// partially in range, check longer prefix
min(2,1): x = 11, y = 11*1*1 = 11 < 100
max(2,1): x = 19, y = 19*1*9 = 171 > 100
// partially in range, check longer prefix
sp(11..16) <= sp(16) = 96 < 100
sp(17) = 119 // in range - increment count
sp(18) = 144 // in range - increment count
sp(19) = 171 // in range - increment count
min(2,2): x = 21, y = 21*2*1 = 42 < 100
max(2,2): x = 29, y = 29*2*9 = 522 > 200
// partially in range, check longer prefix
// others outside of range, omitted for brevity
sp(23) = 138 // in range - increment count
sp(24) = 192 // in range - increment count
min(2,3): x = 31, y = 31*3*1 = 93 < 100
max(2,3): x = 39, y = 39*3*9 = 1053 > 200
// partially in range, check longer prefix
// others outside of range, omitted for brevity
sp(32) = 192 // in range - increment count
min(2,4): x = 41, y = 41*4*1 = 164 < 200
max(2,4): x = 49, y = 49*4*9 = 1764 > 200
// partially in range, check longer prefix
// others outside of range, omitted for brevity
sp(41) = 164 // in range - increment count
min(2,5): x = 51, y = 51*5*1 = 255 > 200
// not in range, nothing to do
// no need to process (2,6..9), since these are all > min(2,5) > 200
// check 3 digits
min(3,): x = 111, y = 111*1*1*1 = 111 < 200
max(3,): x = 999, y = 999*9*9*9 = 728271 > 200
// partially in range, check longer prefix
min(3,1): x = 111, y = 111*1*1*1 = 111 < 200
max(3,1): x = 199, y = 199*1*9*9 = 16119 > 200
// partially in range, check longer prefix
min(3,11): x = 111, y = 111*1*1*1 = 111 < 200
max(3,11): x = 119, y = 119*1*1*9 = 1071 > 200
// partially in range, check longer prefix
// others outside of range, omitted for brevity
sp(111) = 111 // in range - increment count
min(3,12): x = 121, y = 121*1*2*1 = 242 > 200
// not in range, nothing to do
// no need to process (3,13..19), since these are all > min(3,12) > 200
min(3,2): x = 211, y = 211*2*1*1 = 411 > 200
// not in range, nothing to do
// no need to process (3,3..9), since these are all > min(3,2) > 200
// check 4 digits
min(4,): x = 1111, y = 1111*1*1*1 = 1111 > 200
// not in range, nothing to do
// no need to check more digits, since min(n,) > min(n-1,) and min(4,) > 200
因此,总计数为8个自产品,产生的范围为100到200.
请注意,有时我会检查范围的开始,有时候检查结束。这只是为了说明在特定情况下哪些条件很重要。
为了说明一些事情,如果范围是1-200,则具有前缀1的2位数字的范围将如上所述为[11,171],并且1 <= 11 <= 171 <= 200 ,所以我们可以只包括前缀为1的所有2位数字,其中有9个。
<强>实施强>
我写了一个基本实现的Java程序。对于60000到100000000000,它需要不到一秒,对于更大的数字(甚至在这个范围内),因为实现,会有算术溢出,所以所用的时间不能真正被信任(除此之外,我希望它应该只需要更长时间(对于此范围),而不是更短)。
final static long[] tenPowers = {1, 10, 100, 1000, 10000, 100000, 1000000,
10000000, 100000000, 1000000000, 10000000000l, 100000000000l,
1000000000000l, 10000000000000l, 100000000000000l, 1000000000000000l,
10000000000000000l, 100000000000000000l, 1000000000000000000l};
public static void main(String args[]) throws InterruptedException
{
System.out.println("Count = "+selfProductCountRange(60000, 100000000000l));
}
static long selfProductCountRange(long s, long f)
{
start = s;
finish = f;
long count = 0;
for (len = 1; ; len++)
{
long temp = selfProductCount(0, 0);
if (temp == -1)
break;
count += temp;
}
return count;
}
static long selfProduct(long num)
{
// pretend 0s are 1s for simplicity in the rest of the code
long selfProduct = num;
while (num > 0)
{
selfProduct *= Math.max(num % 10, 1);
num /= 10;
}
return selfProduct;
}
static long start, finish;
static int len;
static long selfProductCount(long prefix, int prefixLen)
{
long max = selfProduct((prefix+1) * tenPowers[len - prefixLen] - 1);
// overflow hack
if (max < 0)
max = finish+1;
if (max < start)
return 0;
long min;
if (prefixLen != 0)
min = selfProduct(prefix * tenPowers[len - prefixLen]);
else
min = selfProduct(tenPowers[len-1]);
if (min > finish)
return -1;
if (max <= finish && min >= start)
return getPossibilities(prefixLen);
long val = 0;
for (int i = 1; i < 10; i++)
{
long temp = selfProductCount(prefix*10+i, prefixLen+1);
if (temp == -1)
break;
val += temp;
}
return val;
}
static long getPossibilities(int prefixLen)
{
return (long)Math.pow(9, len-prefixLen);
}
答案 1 :(得分:0)
所以我们说产品是由digits
和number
组成的。
只需枚举数字()并检查每个排列(形成数字),看看它是否在范围内。
明显的修剪是当数字和最小排列的乘积大于上限时,你返回。
我认为32位整数足够快。