1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| 思路: 给主树的每个节点都计算一个hash值,hash值根据树当前节点的深度和值计算,子树计算根节点的hash值, 如果子树根节点的hash值在主树内存在,证明子树是主树的子树
代码: const MAX_N = 1005; const MOD = 1000000007; public $p = [];
public $hS = []; public $hT = [];
function getPrime() { // 记录质数下标的数组 $isPrime = array_fill(0, self::MAX_N, true); $isPrime[0] = $isPrime[1] = false; // 记录质数的数组 $primes = []; for ($i = 2; $i < self::MAX_N; $i++) { if ($isPrime[$i]) { // 下标为true,记录质数 $this->p = $i; }
foreach ($this->p as $prime) { if ($i * $prime >= self::MAX_N) { // 超过指定范围,break break; }
// 指定不为质数的下标 $isPrime[$prime * $i] = false; if ($i % $prime === 0) { // 防止重复设定质数下标 break; } } }
return $primes; }
function dfs($o, &$h) { // 获取每个节点对象在系统中的id,作为唯一键 $id = spl_object_id($o); $h[$id] = ["f" => $o->val, "s" => 1];
if ($o->left === null && $o->right === null) { return; } if ($o->left !== null) { $this->dfs($o->left, $h); $lid = spl_object_id($o->left); $h[$id]["s"] += $h[$lid]["s"]; // hash值算法,左节点 31 // 使用$this->p 降低哈希碰撞的概率,降低hash值重复的概率 // % self::MOD用来限制结果不能大于self::MOD,防止结果溢出 $h[$id]["f"] = ($h[$id]["f"] + (31 * $h[$lid]["f"] * $this->p[$h[$lid]["s"]]) % self::MOD) % self::MOD; } if ($o->right !== null) { $this->dfs($o->right, $h); $rid = spl_object_id($o->right); $h[$id]["s"] += $h[$rid]["s"]; // hash值算法,右节点 179 // 使用$this->p 降低哈希碰撞的概率,降低hash值重复的概率 // % self::MOD用来限制结果不能大于self::MOD,防止结果溢出 $h[$id]["f"] = ($h[$id]["f"] + (179 * $h[$rid]["f"] * $this->p[$h[$rid]["s"]]) % self::MOD) % self::MOD; } }
function isSubtree($s, $t) { // 求质数 $this->getPrime(); // 将树s中每个节点的hash值记录到hS数组中 $this->dfs($s, $this->hS); // 将树t中每个节点的hash值记录到hT数组中 $this->dfs($t, $this->hT);
// 获取树t根节点下标 $tid = spl_object_id($t); // 获取树t根节点的hash值 $tHash = $this->hT[$tid]["f"];
foreach ($this->hS as $v) { // 查询树t根节点的hash值是否存在与hS中,存在证明树t是树s的子树 if ($v["f"] === $tHash) { return true; } }
return false; }
|