匹配字符串上的值的总和

时间:2014-01-27 11:57:43

标签: php algorithm node.js combinations permutation

我有一串用空格分隔的数值:

70 58 81 909 70 215 70 1022 580 930 898 70 276 31 11 **920 898** 1503 195 770 573 508 1015 31 8 815 1478 31 1022 31 1506 31 **318 500 358 865** 358 991 518 58 450 420 487 31 1478 108 70 1022 31 215 318 500 61 31 655 1061 918 54 898 31 8 1011 9 8 459 346 770 751 31 346 770 880 1171 688 1680 31 1002 769 500 61 8 702 898 8 1206 31 709 565 8 138 58 215 81 1171 31 288 500 380 70 284 1500 565 31 601 55 1501 490 565 530 56 990 380 1061 770 345 1171 31 55 1100 605 1471 1234 **31 470 725 358 114 56 9 55** 1100 1610 1471 1000 971 565 55 1100 1610 1061 770 345 949 31 370 52 688 1680 770 880 1171 163 249 151 489 653 56 990 380 503 490 770 1376 1056 31 8 64 490 565 55 108 56 1178 501 653 898 860 565 31 315 61 509 108 501 653 31 349 249 151 489 246 56 990 380 1070 573 1663 725 821 31 70 373 1171 490 565 55 108...

我想得到所有出现的字符串,其中数字的总和是x。所以,如果我搜索:2041它应该返回一个数组(“318 500 358 865”)或者如果我搜索:1818它应该返回一个数组(“920 898”,“31 470 725 358 114 56 9 55”)。 / p>

我还需要最优解决方案,因为数字串可以总计达数十万。

理论上解释的原理会很好,但如果解决方案是由编程语言给出的,则首选语言是PHP或NodeJ。如果可能的话,即使MySQL解决方案也会很好。但无论如何,任何语言的解决方案都会很好。

额外备注

  • 数字都是正整数
  • 数值介于1-10000
  • 之间

2 个答案:

答案 0 :(得分:0)

用法:

$ex = new finder($string);
$result = $ex->search(979)->find(true); // true = Hard mode

首先我们传递我们想要搜索的字符串,然后我们使用方法to_array(),这样我们就可以从字符串创建数组,然后你需要选择你想要使用的模式。

它有2种模式,软搜索和硬搜索。

你可以选择在find方法中使用哪一个,> find(true),True = hard mode,False = soft mode;

软模式非常简单,创建一个新的多维数组,其中键作为数字的strlen(方法order()),所以如果我们搜索数字70,我们真的不想使用3位数字或更多,我的意思是(100,99999等...)。然后它只是用数字减去搜索值,并尝试使用(in_array)搜索整个数组中是否有结果;

foreach ($this->_clean as $clean) {
            $minus = abs($clean - $search);

            // Simple and fast query
            if(in_array($minus, $this->_clean)){
               $tmp[] = array($minus,$clean);
            }

 }

硬模式和名称一样,我们将遍历每个数字。

 public function hard_search($array, $partial){

       $s = 0;

       foreach ($partial as $x){
           $s += $x;
       }

       if ($s == $this->_search){
            $this->_tmp[] = $partial;
       }

       if ($s < $this->_search){
           for($i=0;$i<count($array);$i++) {
                $remaining = array();
                $n = $array[$i];

                for ($j=$i+1; $j<count($array); $j++) {
                    array_push($remaining, $array[$j]);
                };

                $partial_rec = $partial;
                array_push($partial_rec, $n);

                $this->hard_search($remaining,$partial_rec);
          }
       }

        return $this->_tmp;
    }

当然,我们可以做一些更多的调整,但从我测试的结果可以得到很好的结果。 如果您有任何问题,请随时询问。

输出示例:http://codepad.viper-7.com/INvSNo     

class finder {

   public $stop;

   protected $_string,
             $_search,
             $_tmp,
             $_array = array(),
             $_array_order = array(),
             $_clean = array();

   public function __construct($string){
       $this->_string = $string;
   }

   /**
    * String to array
    * 
    * @return \find
    */
   public function to_array(){
       $this->_array = array_keys(
          array_flip(
               explode(' ', $this->_string)
             )
         );

       return $this;
   }

   /**
    * what we are searching for
    * 
    * @param string/int $search
    * @return \finder
    */
   public function search($search){
       $this->reset();
       $this->_search = $search;
       $this->to_array();
       return $this;
   }


    /**
    * 
    * @param type $a // array
    * @param type $total // total
    * @return array
    */
   public function find($hard = false){ 

        $this->_hard = $hard;

        if(is_array($this->_search)){
            foreach($this->_search as $search){
               $result[] = $this->search_array($search);
            }
        }else{
            $result = $this->search_array($this->_search);
        }

        return $result;
    }

   /**********************************
    * SOFT SEARCH
    ***********************************/

   /**
    * Multidimensional Array with strlen as the key
    * 
    * @return \find
    */
   public function order(){

        // Order 
        foreach($this->_array as $n){
            $this->_array_order[strlen($n)][] = $n;
        }

        return $this;
   }

   public function clean($search){

       $tmp = array();

        $check_length = function($number) use($search){

            if($number <= $search){
                return $number;
            }
            return false;
        };

        foreach(range(key($this->_array_order), strlen($search)) as $v){

            $tmp = array_map($check_length,array_merge($tmp, $this->_array_order[$v]));  
        }

        $this->_clean = array_filter($tmp);

        sort($this->_clean);

        return $this;
   }

   public function search_array($search) {

        $res = array();

        if($this->_hard == false){
          $this->order();
          $this->clean($search);
          $res = $this->soft_search($search);
        }else{

           $res = $this->hard_search($this->_array, array());
        }

        return $res;
    }

   /**
     * 
     * @return array
     */
    public function soft_search($search){

        $tmp = array();

        foreach ($this->_clean as $clean) {
            $minus = abs($clean - $search);

            // Simple and fast query
            if(in_array($minus, $this->_clean)){
               $tmp[] = array($minus,$clean);
            }

        }
        return $tmp;
    } 

   /**********************************
    * END SOFT SEARCH
    ***********************************/ 

   public function hard_search($array, $partial){

       $s = 0;

       foreach ($partial as $x){
           $s += $x;
       }

       if ($s == $this->_search){
            $this->_tmp[] = $partial;
       }

       // if higher STOP
       if ($s < $this->_search){
           for($i=0;$i<count($array);$i++) {
                $remaining = array();
                $n = $array[$i];

                for ($j=$i+1; $j<count($array); $j++) {
                    array_push($remaining, $array[$j]);
                };

                $partial_rec = $partial;
                array_push($partial_rec, $n);

                $this->hard_search($remaining,$partial_rec);
          }
       }

        return $this->_tmp;
    }



   /****************************
    * 
    * Extra
    * 
    *****************************/ 

   public function reset(){
        $this->_search = '';
        $this->_clean = array();
        $this->_array = array();
        $this->_array_order = array();
        $this->_tmp = array();
        $this->_tmp = array();
        return $this;

   }

   public function new_string($string){

       $this->reset();
       $this->_string = $string;
       $this->to_array();

       return $this;
   }
}

$string = '70 58 81 909 70 215 130 70 1022 580 930 898 70 276 31 11 920 898 1503 195 770 573 508 '
        . '1171 490 565 55 108';

$ex = new finder($string);

echo '<pre>';
echo '<h1>Hard 979</h1>';
$result = $ex->search(979)->find(true);
print_r($result);

echo '<h1>Soft 979</h1>';
$result = $ex->search(979)->find();
print_r($result);

echo '<h1>Hard 238</h1>';
$result = $ex->search(238)->find(true);
print_r($result);

echo '<h1>Soft 238</h1>';
$result = $ex->search(238)->find();
print_r($result);

285的输出示例:

Hard 285

Array
(
    [0] => Array
        (
            [0] => 70
            [1] => 215
        )

    [1] => Array
        (
            [0] => 58
            [1] => 130
            [2] => 31
            [3] => 11
            [4] => 55
        )

)
Soft 285

Array
(
    [0] => Array
        (
            [0] => 215
            [1] => 70
        )

)

答案 1 :(得分:-1)

在这里,您可以使用Python。这具有线性复杂性:

def list2string( alist ):
    return " ".join( map(str, alist ))

def string2list( s ):
    return list(map( int, s.split() ))

def find_number( a, total ):
    u = 0
    y = 0 # the current sum of the interval (u .. v)
    res = []
    for v in range( 0, len(a) ):
        # at this point the interval sum y is smaller than the requested total,
        # so we move the right end of the interval forward
        y += a[v]
        while y >= total:
            if y == total:
                res.append( list2string( a[ u : v+1 ] ) )
            # if the current sum is too large, move the left end of the interval forward
            y -= a[u]
            u += 1
    return res



text = "70 58 81 909 70 215 70 1022 580 930 898"
alist = string2list(text)
print( find_number( alist, 285) )

我假设列表中没有负值,列表纯粹由空格分隔的整数组成。将它翻译成任何其他语言都不应该有任何问题。我希望算法是不言自明的,如果没有问的话。