找到二叉树的叶子

时间:2017-02-24 00:18:49

标签: ruby algorithm recursion tree

处理以下问题:

Canvasfun

我的想法是一个简单的递归算法,如下所示。想法是找到左子树和右子树的叶子,并编织它们使得深度在右子阵列中。我已经非常彻底地测试了“编织”方法,我认为这很好。我关注的是我的递归实现 - 我正在从正确的方法中找到答案,并且不确定原因。

以下是带有示例输入/输出的代码:

Given a binary tree, collect a tree's nodes as if you were doing this: Collect and remove all leaves, repeat until the tree is empty.

Example:
Given binary tree 
          1
         / \
        2   3
       / \     
      4   5    
Returns [4, 5, 3], [2], [1].

Explanation:
1. Removing the leaves [4, 5, 3] would result in this tree:

          1
         / 
        2          
2. Now removing the leaf [2] would result in this tree:

          1          
3. Now removing the leaf [1] would result in the empty tree:

          []         
Returns [4, 5, 3], [2], [1].

示例输入/输出/正确答案:

def find_leaves(root)
    return [] if root.nil?
    #create leaf_arr of root.left and root.right
    #weave them in order.
    #add the root

    left_arr = find_leaves(root.left)
    right_arr = find_leaves(root.right)


    weave(left_arr, right_arr) << [root]
end


def weave(arr1, arr2) #these are 2d arrs
    i = 0
    until i == arr1.length || i == arr2.length #potential nil/empty case here
        arr1[i] += arr2[i]
        i += 1
    end
    if i < arr2.length  
        #either arr 1 or arr2 isn't finished. if arr1 isn't finished, we're done. if arr2 isnt finished, do the below:
        until i == arr2.length
            arr1 << arr2[i]
            i += 1
        end
    end
    arr1
end

我已经打印了left_arr和right_arr变量的输出,它们看起来很好,我对我的编织算法进行了压力测试。我在概念上是在这里吗?

3 个答案:

答案 0 :(得分:1)

我不能评论所以我会这样做。 (记得我不懂红宝石) 我认为双重数组(root.left和root.right)的定义方式已经出现了问题。他们是如何定义的?如何定义root?

但以下解释了整个阵列的重复。

weave(left_arr, right_arr) << [root]   

这应该与此相符。

weave(left_arr, right_arr) << [root.root]

否则,您将追加整个根数组[1,2,3,4,5]。 所以这解释了最后一部分的添加。 [[[4],[5],[3]],[[2,4,5]],[[1,2,3,4,5]]]

我在编织中发现错误的建议是在每个阶段打印arr1和arr2 .... 你能表明......

答案 1 :(得分:1)

在您的代码中,您使用的是纯粹的深度优先搜索算法DFS,并且使用该算法,我认为您很难通过编织函数进行数组切换来实现目标。因为您的树将按此顺序处理4,5,2,3,1。 一种解决方案是使用迭代(伪代码):

function doJob(root) begin
  leaves = findLeaves(root)
  while leaves.size > 0 do begin
    for each leaf in leaves delete(leaf)
    leaves = findLeaves(root)
  end
  delete(root)
end

function findLeaves(node) begin
  if node = nil then begin
    return []
  end
  else begin
    leftLeaves = findLeaves(node.left)
    rightLeaves = fingLeaves(node.right)
    leaves = leftLeaves + rightLeaves
    if leaves.size == 0 then begin
      leaves.add(node)
    end
    return leaves
  end
 end

答案 2 :(得分:1)

因为当我搜索你的标题时,这仍然是开放的并且看起来很公平。我将展示一个非常有表现力的解决方案:

def find_leaves(root)
  return [] if root.nil?
  return [[root.val]] if root.left.nil? && root.right.nil?
  todo = [root]
  leaves = []

  until todo.empty?
    top = todo.shift
    %w[left right].each do |path|
      leaf = top.send(path)
      next if leaf.nil?
      if leaf.left.nil? && leaf.right.nil?
        leaves << leaf.val
        top.instance_variable_set("@#{path}", nil)
      else
        todo << leaf
      end
    end
  end
  [leaves].concat(find_leaves(root))
end

更重构的版本:

def find_leaves(root)
  leaves = []
  search = lambda do |branch|
    return -1 unless branch
    i = 1 + [search[branch.left], search[branch.right]].max
    (leaves[i] ||= []) << branch.val
    i
  end
  search[root]
  leaves
end

它们的速度大致相同,而且第一个更容易阅读和理解。