查找无数个数字的总和的第一个出现

时间:2019-12-29 22:37:22

标签: php math search numbers

对于诸如Pi之类的无穷数字,如何找到给定数字n的数字精确总和的首次出现。

例如。如果n = 20

Pi = 3.14159265358979323846264338327950950288419716939 ...

然后第一次出现是从数字1到数字5,因为: 1 + 4 + 1 + 5 + 9 = 20

如果n = 30,则第一次出现是从数字5到数字11 因为9 + 2 + 6 + 5 + 3 + 5 = 30

answer应该有一个有效的php演示

3 个答案:

答案 0 :(得分:2)

对此的答案是使用滑动窗口来保持总和。因此,请保持两个指针分别为ij。继续增加j并在其中添加元素。当它超过期望的总和i并减少i处的元素。然后继续增加j,直到达到和或溢出为止,然后重复上述过程。

示例总和= 30

1 41592653589793238 >> i = j = 0 current_sum = 1

1415926 53589793238 >> i = 0 j = 6 current_sum = 28

在下一次迭代中加5将导致current_sum> 30,因此您将i递增

1 415926 53589793238 >> i = 1 j = 6 current_sum = 27

14 15926 53589793238 >> i = 2 j = 6 current_sum = 23

14 159265 3589793238 >> i = 2 j = 7 current_sum = 28

继续这种方式,它将最终到达等于sum = 30的窗口。那应该使您摆脱困境,并帮助您找到答案。

答案 1 :(得分:1)

方法1(由Ashwin Bhat建议)

此实现使用两个枢轴。计算$pivot_a$pivot_b之间的数字总和。根据总和的值,我们增加$pivot_b(如果总和较小)或$pivot_a(如果总和较大)。如果总和等于$n,请中断。枢轴的值会给出适当的数字索引。

$pi = "314159265358979323846264338327950288419716939";

$n = 30;

$pivot_a = $pivot_b = 0;
$sum = 0;

for( ; $pivot_b < strlen($pi); ) {

    if($sum < $n) {
        $sum += $pi[$pivot_b++];
    } elseif ($sum > $n) {
        $sum -= $pi[$pivot_a++];
    } else {
        print('Solution found from digit '.$pivot_a.' to '.$pivot_b.'.');
        exit;
    }
}

print('No match was found.');

方法2

此实现仅使用一个枢轴,从该枢轴开始对数字求和。如果总和恰好大于期望值,则会将总和重置为零,将枢轴移动一个位置,然后再次开始求和。


$pi = "314159265358979323846264338327950288419716939";

$n = 30;


// Let's sum up all the elements from $pivot until we get the exact sum or a 
// number greater than that. In the latter case, shift the $pivot one place.

$pivot = 0;
$sum = 0;

for($k=0 ; $sum != $n && $k < strlen($pi) ; $k++) {
    $sum += $pi[$k];

    print($pi[$k]);

    if($sum > $n) {
        print(' = '.$sum.'  fail, k='.($pivot+1).PHP_EOL);
        $sum = 0;
        $k = $pivot++;
    } elseif($sum < $n) {
        print("+");
    }
}

print(' = '.$n.' found from digit '.$pivot.' to '.$k.'.');

实现不是很有效,但是尝试解释这些步骤。它打印

3+1+4+1+5+9+2+6 = 31  fail, k=1
1+4+1+5+9+2+6+5 = 33  fail, k=2
4+1+5+9+2+6+5 = 32  fail, k=3
1+5+9+2+6+5+3 = 31  fail, k=4
5+9+2+6+5+3 = 30 found from digit 4 to 10.

答案 2 :(得分:0)

这是另一种方法。它沿此过程建立一个求和数组,并在每次迭代时尝试将当前数字加到先前的求和上,依此类推,同时始终只保留仍然相关的和(<目标)。

函数要么返回:

  • 由2个值组成的数组,表示数字从0开始的索引间隔
  • null(如果找不到目标金额)

代码:

function findFirstSumOccurrenceIndexes(string $digits, int $targetSum): ?array
{
  $sums = [];

  for ($pos = 0, $length = strlen($digits); $pos < $length; $pos++) {
    $digit = (int)$digits[$pos];
    if ($digit === $targetSum) {
      return [$pos, $pos];
    }
    foreach ($sums as $startPos => $sum) {
      if ($sum + $digit === $targetSum) {
        return [$startPos, $pos];
      }
      if ($sum + $digit < $targetSum) {
        $sums[$startPos] += $digit;
      }
      else {
        unset($sums[$startPos]);
      }
    }
    $sums[] = $digit;
  }

  return null;
}

演示:https://3v4l.org/9t3vf