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
| 思路: 使用Morris中序二叉树,中序遍历,顺序左中右,将当前左子树的最右边的节点设置为跳转节点,最后遍历到跳转节点会跳回到之前的节点
class TreeNode { public $val = null; public $left = null; public $right = null;
function __construct($val = 0, $left = null, $right = null) { $this->val = $val; $this->left = $left; $this->right = $right; } }
private $base; private $count = 0; private $maxCount = 0; private $answer = [];
private function update($val) { if ($val === $this->base) { $this->count++; } else { $this->count = 1; $this->base = $val; }
if ($this->count === $this->maxCount) { $this->answer[] = $val; }
if ($this->count > $this->maxCount) { $this->maxCount = $this->count; $this->answer = [$val]; } }
/** * @param TreeNode $root * * @return Integer[] */ public function findMode($root) { $cur = $root; while ($cur) { if ($cur->left === null) { // 左子树为空,更新数据,进入右子树 $this->update($cur->val); // 空的右子树会有临时节点替代,相当于跳转回上一级的节点 $cur = $cur->right; continue; }
// 左子树 $pre = $cur->left; while ($pre->right !== null && $pre->right !== $cur) { // 进入左子树最右边的节点,是中序遍历左子树的最后一个节点 $pre = $pre->right; }
if ($pre->right === null) { // 第一步,创建左子树的最右临时节点,映射到当前节点 // 相当于给每个左子树的最右节点创建一个临时节点,方便用来跳转回映射的节点 $pre->right = $cur; // 进入左子树 $cur = $cur->left; } else { // 第二步,最右的临时节点已经生成,删除临时节点并进入右子树 // 删除临时建立的节点,不还原二叉树可以不删除 $pre->right = null; $this->update($cur->val); // 进入右子树 $cur = $cur->right; } }
return $this->answer; }
|