优化算法以查找满足特定属性的六位数字的数量

时间:2012-10-25 00:34:43

标签: c++ algorithm

问题:“一种算法,用于查找六位数字的数字,其中前三位数的总和等于后三位数的总和。”

我在一次采访中遇到了这个问题,想知道最好的解决方案。这就是我现在所拥有的。

方法1:当然,蛮力解决方案是检查每个数字(在100,000和999,999之间),前三位和后三位的总和是否相等。如果是,则递增某个计数器,该计数器保持所有这些数字的计数。

但这会检查所有900,000个数字,因此效率低下。

方法2:由于我们被问到“有多少”这样的数字而不是“哪个数字”,我们可以做得更好。将数字分为两部分:前三个数字(从100到999)和后三个数字(从000到999)。因此,候选数字的任一部分中的三个数字的总和可以在1到27的范围内 *为每个部分保持std::map<int, int>,其中键是总和,值是相应部分中具有该总和的数字(3位数)。
*现在,对于第一部分中的每个数字,找出它的总和并更新相应的地图 *同样,我们可以获得第二部分的更新地图。 *现在通过乘以相应的对(例如,键4的映射1中的值和键4的映射2中的值)并将它们相加,我们得到答案。

在这种方法中,我们最终检查1K数字。

我的问题是我们如何进一步优化?有更好的解决方案吗?

5 个答案:

答案 0 :(得分:6)

对于0 <= s <= 18,有10 - |s - 9|种方法可以获得s两位数的总和。

所以,第一部分

int first[28] = {0};
for(int s = 0; s <= 18; ++s) {
    int c = 10 - (s < 9 ? (9 - s) : (s - 9));
    for(int d = 1; d <= 9; ++d) {
        first[s+d] += c;
    }
}

这是19 * 9 = 171次迭代,对于后半部分,类似地做,内部循环从0开始而不是1,即19 * 10 = 190次迭代。然后将first[i]*second[i]1 <= i <= 27相加。

答案 1 :(得分:1)

生成所有三位数字;根据它们的数字总和将它们分成几组。 (实际上,你需要做的就是保持一个计算集合大小的向量)。对于每个集合,可以生成的六位数字的数量是集合平方的大小。总结设定大小的方块以获得答案。

int sumCounts[28]; // sums can go from 0 through 27
for (int i = 0; i < 1000; ++i) {
    sumCounts[sumOfDigits(i)]++;
}
int total = 0;
for (int i = 0; i < 28; ++i) {
    count = sumCounts[i];
    total += count * count;
}

编辑用于消除计数前导零的变化:

int sumCounts[28];
int sumCounts2[28];
for (int i = 0; i < 100; ++i) {
    int s = sumOfDigits(i);
    sumCounts[s]++;
    sumCounts2[s]++;
}
for (int i = 100; i < 1000; ++i) {
    sumCounts[sumOfDigits(i)]++;
}
int total = 0;
for (int i = 0; i < 28; ++i) {
    count = sumCounts[i];
    total += (count - sumCounts2[i]) * count;
}

答案 2 :(得分:1)

Python实施

def equal_digit_sums():
dists = {}
for i in range(1000):
    digits = [int(d) for d in str(i)]
    dsum = sum(digits)
    if dsum not in dists:
        dists[dsum] = [0,0]
    dists[dsum][0 if len(digits) == 3 else 1] += 1
def prod(dsum):
    t = dists[dsum]
    return (t[0]+t[1])*t[0]
return sum(prod(dsum) for dsum in dists)

print(equal_digit_sums())

结果:50412

答案 3 :(得分:0)

一个想法:对于0到27之间的每个数字,计算具有该数字总和的三位数字的数量。使用DP风格的方法应该可以有效地实现这一目标。

现在你只是对结果的平方进行求和,因为对于每个答案,你可以用一个六位数字来表示每一个。

答案 4 :(得分:0)

假设不允许前导0,您想要计算有多少种不同的方式与3个数字相加n。要计算你可以在for循环中有一个for循环。所以:

firstHalf = 0
for i in xrange(max(1,n/3),min(9,n+1)): #first digit
  for j in xrange((n-i)/2,min(9,n-i+1)): #second digit
    firstHalf +=1  #Will only be one possible third digit
secondHalf = firstHalf + max(0,10-|n-9|)

如果您要对数字求和,则始终唯一确定最后一个数字。因此,在第一个数字为0的情况下,我们只计算第二个数字可能有多少个不同的值。如果n小于10,则这将是n + 1.如果n更大,则直到18,它将是19-n。超过18岁,没有办法形成总和。 如果你遍历所有n,1到27,你将获得总和。

相关问题