在PHP中查找字符串中最常出现的3个子字符串

时间:2015-07-22 05:10:30

标签: php arrays string

我想重温这些思维过程,因为我不知道如何改进这一点。我有一个用逗号分隔的字符串,它们有重复出现的子串,我想找到3个最常出现的子字符串。

  • 我打算用逗号将字符串分解为数组。
  • 在数组中的每个元素的原始字符串中执行substr_count,并将其存储在单独的数组中以存储计数? (不知道如何改进,因为这会为同一个子串创建重复计数)
  • 在阵列上执行最大值以查找第一个,第二个和第三个最常出现的子串。
  • 返回一个包含第一,第二和第三个最常出现的子串的数组。

我在进行爆炸后猜测,我可以快速排序并从那里开始?

这是我到目前为止所尝试的:

$result = findThreeMostOccuringStrings("apple, apple, berry, cherry, cherry, cherry, dog, dog, dog");
var_dump($result);

function findThreeMostOccuringStrings($str){
    $first = PHP_INT_MIN;
    $second = PHP_INT_MIN;
    $third = PHP_INT_MIN;

    $arr = explode(",", $str);

    for ($i = 0; $i < count($str); $i++){
        $arrIdx[] = substr_count($arr[$i]);
    }

    $first = max($arrIdx);
    $arrIdx[$first] = -1;

    $second = max($arrIdx);
    $arrIdx[$first] = -1;

    $third = max($arrIdx);
    $arrIdx[$first] = -1;

    $threeMostOccuringStrings = array($first, $second, $third);

    return $threeMostOccuringStrings;
}

3 个答案:

答案 0 :(得分:1)

如果by substring只表示用逗号分隔的字符串而不是这些字符串的子字符串,请在爆炸后使用array_count_values

答案 1 :(得分:0)

如果您正在寻找一种有效的方法来解决子字符串搜索,那么答案就是Trie前缀树。这基本上减少了搜索子字符串的查找时间,因为它为所有前缀创建了一个确定性路径(即前缀树)。

考虑字符串"A cat does not categorize its food while among other cats."此处,子字符串categorizecats都共享cat的相同前缀。因此,如果计算源自根中每个分支的EOW个节点的数量,那么在前缀树中查找最常用的子字符串很容易。

构建树也很简单。

function insertString($str, $trie) {
    $str = strtolower($str); // normalize case
    $node = $trie;
    foreach(str_split($str) as $letter) {
        if (!isset($node->$letter)) {
            $node->$letter = new stdClass;
        }
        $node = $node->$letter;
    }
    $node->EOW = true; // place EOL node
}

function countNodes($branch) {
    $n = 0;
    foreach($branch as $e => $node) {
        if ($node instanceof stdClass) {
            $n += countNodes($node);
        } elseif ($e === 'EOW') {
            $n++;
        }
    }
    return $n;
}

$trie = new stdClass;

$str = "A cat does not categorize its food while among other cats";

foreach(explode(' ', $str) as $word) {
    insertString($word, $trie);
}

$s = [];
foreach($trie as $n => $rootNodes) {
    $s[$n] = countNodes($rootNodes);
}
var_dump($s);

哪个应该给你......

array(8) {
  ["a"]=>
  int(2)
  ["c"]=>
  int(3)
  ["d"]=>
  int(1)
  ["n"]=>
  int(1)
  ["i"]=>
  int(1)
  ["f"]=>
  int(1)
  ["w"]=>
  int(1)
  ["o"]=>
  int(1)
}

从那里你可以看到根分支c具有最多的子串数(如果步行匹配catcatscategorize

答案 2 :(得分:0)

根据您的帖子和评论,您实际上想要在逗号分隔的术语列表中计算术语,然后对它们进行排名,所以:让我们这样做,使用关联数组进行计数和arsort到按值反向排序关联数组(以便最高计数位于数组的开头):

function rank($input) {
  $terms = explode(',', $input);
  $ranked = array();
  foreach($terms as $word) {
    $word = trim($word);
    if (!isset($ranked[$word])) {
      $ranked[$word] = 0;
    }
    $ranked[$word]++;
  }
  arsort($ranked);
  return $ranked;
}

因此,如果我们通过print_r(rank("apple, apple, berry, cherry, cherry, cherry, dog, dog, dog"))运行,我们会得到:

Array
(
  [dog] => 3
  [cherry] => 3
  [apple] => 2
  [berry] => 1
)

出色。