小菜鸡学算法之 226.翻转二叉树

136 阅读2分钟

226 翻转二叉树

image.png

思路

  1. 此题可以使用多种方法:一方面选择前序,后序,中序,层序等。一方面选择递归方式或者迭代方式。总体思想就是:将二叉树全部遍历一遍,然后翻转

解决问题中

  1. 我选择的方式:递归版本前序遍历

    function invertTree(root){ // 作用域1
      function invertNode(left,right){ // 作用域2
        let temp = left
            left = right
            right = temp
        // 把我难住的地方:需要将交换之后的值赋值给root节点    
        root.left = left  
        root.right = right
      }
      invertNode(root.left,root.right)  // 调用交换函数,使得节点的值两两交换
      
      invertTree(root.left)  // 将left左子树进行递归处理
      invertTree(root.right) // 将right右子树进行递归处理
      return root
    }
    

疑难点: 这道题中把我难住的地方,是交换函数中的后面两步,不明白为什么要赋值给root,我以为它多此一举,但是如果没有这两句的话 ,结果并不会发生翻转。

想了一下,也许这跟引用数据类型和简单数据类型的赋值拷贝的知识有关。树就像对象中包着对象,交换函数中好像是已经将他们的值交换成功了,但是由于左右节点是处于root这个对象中的,所以函数外部再次引用他们的时候发现,值并没有发生改变。所以才有了需要 将交换后的值赋值给节点的操作。

但是,我再次想一想,上面的想法是不对的,用简单的例子测试:

let a = 1,b = 2

function ver(l,r){
  let t = l
  l =r
  r = t
  return [l,r]
}
console.log(ver(a,b))  //结果是[2,1] 结果正确

但是一旦在交换函数的外部再次调用这两个变量时,发现并没有改变
console.log(a,b)  // 1,2
let a = {
    a1:1,
    a2:2
}
function ver(l,r){
  let t = l
  l =r
  r = t
  return [l,r]
}
console.log(ver(a.a1,a.a2))  //结果是[2,1] 

console.log(a.a1,a.a2)  // 依旧是 1,2

原因: 在交换函数之外调用变量时,JavaScript是先从调用位置的当前作用域开始查找的,很明显当前作用域是全局作用域 ,所以找到的是 1,2 。外部作用域是不能调用内部作用域中的变量。

解决: 代码中找到的left right节点,是作用域1 中的。不是交换函数 ,也就是作用域2 中交换后的。 因为在交换函数中被赋值的 left right 是在作用域1找到的,所以复制后作用域1中的left right才会改变。所以,在交换函数中,需要进行节点的赋值这一步骤。