单词搜索 II【php版】

前记: 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"]));

结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值