前记: trie数据结构
trie数据结构是基于各个序列前缀构造出来的查找树
如这样的字符序列[‘oath’、‘dog’、‘dig’、‘dogs’];其构造的trie如下:
构造代码如下:
class TrieNode {
public $children = [];
public $word = null;
public function __construct() {}
}
function buildTrie($words) {
// root node
$root = new TrieNode();
foreach ($words as $word) {
// 当前指针先指向根结点
$curNode = $root;
for ($i=0,$len=strlen($word); $i<$len; $i++) {
// 如果字符对应的子结点已经添加,则curNode指向子结点
// 否则添加子结点
if (array_key_exists($word[$i], $curNode->children)) {
$curNode = $curNode->children[$word[$i]];
} else {
$tmpNode = new TrieNode();
$curNode->children[$word[$i]] = $tmpNode;
$curNode = $tmpNode;
}
}
// 叶子结点存储整个路径对应的word的值
$curNode->word = $word;
}
return $root;
}
题目描述
<?php
class TrieNode {
public $children = [];
public $word = null;
public function __construct() {}
}
class Solution {
private $ans = [];
private $dirs = [
[0, 1],
[0, -1],
[1, 0],
[-1, 0],
];
private $rCnt = 0;
private $cCnt = 0;
/**
* @param String[][] $board
* @param String[] $words
* @return String[]
*/
function findWords($board, $words) {
$this->rCnt = count($board);
if ($this->rCnt == 0) {
return [];
}
$this->cCnt = count($board[0]);
if ($this->cCnt == 0) {
return [];
}
$root = $this->buildTrie($words);
foreach ($board as $rIdx => $rowData) {
foreach ($rowData as $cIdx => $cellData) {
if (array_key_exists($cellData, $root->children)) {
$this->searchMoreWordsDFS($board, $root, $rIdx, $cIdx);
}
}
}
return $this->ans;
}
function searchMoreWordsDFS(&$board,TrieNode $parent, $rIdx, $cIdx) {
$char = $board[$rIdx][$cIdx];
$curNode = $parent->children[$char];
// 已找到完整字串,将其加入结果数组
if (!is_null($curNode->word)) {
$this->ans[] = $curNode->word;
$curNode->word = null;
}
// 将当前格子特殊标记, 防止在此次搜索时重复搜索(题目中有提到对于一个格子中的字符,不在一个单词中出现多次)
$board[$rIdx][$cIdx] = '#';
// 继续找更多的
foreach ($this->dirs as $dir) {
$rIdxNew = $rIdx + $dir[0];
$cIdxNew = $cIdx + $dir[1];
if ($rIdxNew>=0 && $rIdxNew<$this->rCnt
&& $cIdxNew>=0 && $cIdxNew<$this->cCnt &&
array_key_exists($board[$rIdxNew][$cIdxNew], $curNode->children)) {
$this->searchMoreWordsDFS($board, $curNode, $rIdxNew, $cIdxNew);
}
}
// 将标记还原
$board[$rIdx][$cIdx] = $char;
// 如果curNode是叶子结点,说明已找到完整字串,且trie中的当前路径已经到头,可将此结点删除(剪枝)
if (count($curNode->children) == 0) {
unset($parent->children[$char]);
}
}
function buildTrie($words) {
// root node
$root = new TrieNode();
foreach ($words as $word) {
// 当前指针先指向根结点
$curNode = $root;
for ($i=0,$len=strlen($word); $i<$len; $i++) {
// 如果字符对应的子结点已经添加,则curNode指向子结点
// 否则添加子结点
if (array_key_exists($word[$i], $curNode->children)) {
$curNode = $curNode->children[$word[$i]];
} else {
$tmpNode = new TrieNode();
$curNode->children[$word[$i]] = $tmpNode;
$curNode = $tmpNode;
}
}
// 叶子结点存储整个路径对应的word的值
$curNode->word = $word;
}
return $root;
}
}
$s = new Solution();
var_dump($s->findWords([["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], ["oath","pea","eat","rain"]));
结果: