数学问题:循环或递归

时间:2009-02-17 17:37:49

标签: php math recursion loops

我试图以一种数字(在php中)将数字分解为例如:

  • 25变为(16,8,1)
  • 8变为(8)
  • 11变为(8,2,1)

我不知道正确的术语是什么,但我认为这个想法很明确。

我的循环解决方案非常简单:

   $number = rand(0, 128);    
   $number_array_loop = array();

   $temp_number = $number;
   while ($temp_number > 0) {
       $found_number = pow(2, floor(log($temp_number, 2)));
       $temp_number -= $found_number;

       $number_array_loop[] = $found_number;
   }

我也有一个递归的解决方案,但我不能在不使用全局变量的情况下工作(不想这样),以下内容接近但会导致数组中的数组:

   function get_numbers($rest_number) {

       $found_number = pow(2, floor(log($rest_number, 2)));

       if ($found_number > 0) {
           $temp_array[] = get_numbers($rest_number - $found_number);
           $temp_array[] = $found_number;
       }

       return $temp_array;
   }

   $number_array_recursive = array();
   $number_array_recursive = get_numbers($number);

但是,使用像 pow(floor(log()))这样的东西似乎对于像这样的简单问题有点多了。

在我看来,问题需要一个非常简单的数学递归解决方案,但我只是没有看到它。

任何帮助都会被贬低。

编辑:二进制是关键,非常感谢!

6 个答案:

答案 0 :(得分:7)

你可以得到数字的二进制表示 - 1表示包括2的幂,0表示不


$binary_number = decbin($test_number);
$binary_string = "${binary_number}";
for ($i = 0; $i < strlen($binary_string); $i++) {
  if ($binary_string[strlen($binary_string) - $i - 1] == "1") {
    $num_out = pow(2, $i);
    print "${num_out} ";
  }
}

这已经过测试并且可以正常工作,但在PHP语法上可能有更好的方法。

答案 1 :(得分:3)

根据我的经验,递归比循环有更多的开销,所以我建议坚持使用循环解决方案。

答案 2 :(得分:3)

您可以使用以下(未经测试的)功能检查输入数字的每一位。

function checkBit($var, $pos)
{
    return ($var & (1 << $pos));
}

通过使用按位AND函数检查变量$ var中位置$ pos的位。为简洁起见,我将向您展示4位数字。

  • 1 = 0001
  • 2 = 0010
  • 4 = 0100
  • 8 = 1000

如果我想检查数字3的位置0(最右边的位),我会调用这样的函数:

$number = 3;
checkBit($number, 0);

在内部,checkBit将常量1向左移动0次,因为我传入了0.然后按顺序AND(&amp;)结果与我传入的数字,3。因为3 = 0011 1 = 0001,结果为真,因为在按位AND运算符的两个参数中都设置了第0位。

答案 3 :(得分:1)

如果你只是做了一点点的事情(比如“num&amp; 0x0001”),并检查该操作的值是否为zeroness,那么通过这些位跳闸应该是微不足道的,如下所示: (我知道这是在java中,但我不知道php,反正它并不是特定于php的问题)

    int number=25;
for (int i = 0; i < 16; i++)
{
    if ((number & 0x0001) != 0)
    {
    System.out.println("" + Math.pow(2, i));
    }
    number = number >> 1;
}

这样的事情在任何语言中都应该是微不足道的。

答案 4 :(得分:1)

将整数分解为2的幂的另一种方法是保持除以2并找到余数。

例如: 25/2 = 12 R 1,功率= 2 ^ 0 = 1

12/2 = 6 R 0,功率= 2 ^ 1 = 2

6/2 = 3 R 0,功率= 2 ^ 2 = 4

3/2 = 1 R 1,功率= 2 ^ 3 = 8

1/2 = 0 R 1,功率= 2 ^ 4 = 16

所以,这里25 = 1 + 8 + 16,因为这些是剩余部分为1的唯一地方。

function powers_of_2($n)
{
    $powers = array();
    $base = 1;
    while ($n > 0)
    {
        if ($n % 2 == 1)
        {
            $powers[] = $base;
        }
        $n = (int)$n/2;
        $base *= 2;
    }
    return $powers;
}

答案 5 :(得分:0)

除非您的数字非常稀疏(即number_array会很小),否则通过所有权力可能会更快。坚持基础2:

function get_powers_of_2($n) {

  // $max_pow = 31;       // faster if you know the range of $n
  $max_pow = log($n, 2);  // safe
  $powers = array();

  for($i = 0; i <= $max_pow; $i++) {
    $pow = 1 << $i;
    if($n & $pow) $powers[] = $pow;
  }
  return $powers;
}