题目

题目来源:力扣(LeetCode)

给你一棵二叉树的根节点 root ,树中有 n 个节点,每个节点都有一个不同于其他节点且处于 1 到 n 之间的值。

另给你一个由 n 个值组成的行程序列 voyage ,表示 预期 的二叉树 先序遍历 结果。

通过交换节点的左右子树,可以 翻转 该二叉树中的任意节点。例,翻转节点 1 的效果如下:
image.png

请翻转 最少 的树中节点,使二叉树的 先序遍历 与预期的遍历行程 voyage 相匹配 。

如果可以,则返回 翻转的 所有节点的值的列表。你可以按任何顺序返回答案。如果不能,则返回列表 [-1]。

示例 1:
image.png

输入:root = [1,2], voyage = [2,1]
输出:[-1]
解释:翻转节点无法令先序遍历匹配预期行程。

示例 2:
image.png

输入:root = [1,2,3], voyage = [1,3,2]
输出:[1]
解释:交换节点 2 和 3 来翻转节点 1 ,先序遍历可以匹配预期行程。

示例 3:
image.png

输入:root = [1,2,3], voyage = [1,2,3]
输出:[]
解释:先序遍历已经匹配预期行程,所以不需要翻转节点。

思路分析

  1. 题目给出了一个待操作的树 A 的根节点 root, 和树 V 先序遍历的结果数组,然后求的是 A 能否翻转最少的 n 个节点,使得 A 和 V 一致。

  2. 我们遍历树V先序遍历的结果数组voyage (其实相当于是前序遍历树V),然后用 V 的值去匹配 A, 看看能否进行树的匹配

  3. 对于一次遍历,我们首先判断根节点的值是一致,才会进入这一次的遍历中,然后主要是看左右树,对于树 V 来说,用 pos 不断按照先序遍历给出值,而对于 V 来说,你可以用左树匹配,如果匹配成功,则啥事没有,大家是一样的;而如果左树不匹配,用右树先行,然后再走左树,这种情况就需要翻转一下当前的节点,保证树 A 要在前序遍历的情况和 V 匹配;

  4. 如果在匹配过程中 A 的左右树都没有匹配成功,则会提前走出 A 的遍历,这个时候 pos 就没有迭代完,也就是树A 的节点数量少于树V 的节点数量,这个时候就是异常,返回 [-1]

  1. /**
  2. * Definition for a binary tree node.
  3. * function TreeNode(val, left, right) {
  4. * this.val = (val===undefined ? 0 : val)
  5. * this.left = (left===undefined ? null : left)
  6. * this.right = (right===undefined ? null : right)
  7. * }
  8. */
  9. /**
  10. * @param {TreeNode} root
  11. * @param {number[]} voyage
  12. * @return {number[]}
  13. */
  14. var flipMatchVoyage = function (root, voyage) {
  15. // 用来在进入 dfs 前对根节点的判断
  16. // 如果根节点的值不一致,则直接返回-1,不再进入dfs
  17. if (root.val !== voyage[0]) return [-1]
  18. const ret = []
  19. let pos = 0 // 这是用来获取 voyage 值,也是遍历树 V 的,如果没有走完,证明无法匹配 root
  20. const dfs = root => {
  21. // 每一次的遍历 pos 都要跟随着
  22. pos++
  23. // 对于每一个节点,都是按照先序遍历的写法
  24. if (root.left && root.left.val === voyage[pos]) {
  25. // 如果在这节点左树适配,那就继续走,因为这是先序遍历
  26. dfs(root.left)
  27. }
  28. if (root.right && root.right.val === voyage[pos]) {
  29. dfs(root.right)
  30. // 右树完成之后,需要看看现在 pos 所在的值是否可以匹配左树,即是否先走右树再走左树,成立即当前的 root 节点就是需要进行翻转的节点
  31. if (root.left && root.left.val === voyage[pos]) {
  32. ret.push(root.val)
  33. dfs(root.left)
  34. }
  35. }
  36. }
  37. dfs(root)
  38. // 代码走到此处,代表树A 已经遍历完了
  39. // 此时 pos 的值代表的就是树A的节点数量,树A 的节点数量少于 树 V 的节点数量,说明不匹配
  40. if (pos < voyage.length) {
  41. return [-1]
  42. }
  43. return ret
  44. };