HomeBrew作者去Google面試做錯的一道題,影響很大,大家一定要研究下這道題。
事件回放
2015 年 6 月 10 日,Homebrew 的作者 @Max Howell 在 twitter 上發(fā)表了如下一內(nèi)容:
Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.
事情大概是說,Max Howell 去 Google 面試,
面試官說:雖然在 Google 有 90% 的工程師用你寫的 Homebrew,但是你居然不能在白板上寫出翻轉(zhuǎn)二叉樹的代碼,所以滾蛋吧。
這件事情如果發(fā)生在任何一個應(yīng)屆生身上,那是再正常不過的了,但是偏偏面試者是有名的 Max Howell。于是乎,關(guān)于應(yīng)該如何面試程序員,再一次被大家熱烈的討論。知乎上也有相關(guān)的討論,如何看待 Max Howell 被 Google 拒絕?
大家也可以看一下 Quora 和 Hacker News 上的討論。
題目
Invert a binary tree.
4
/ \
2 7
/ \ / \
1 3 6 9
to
4
/ \
7 2
/ \ / \
9 6 3 1
解題思路
翻轉(zhuǎn)一個二叉樹,直觀上看,就是把二叉樹的每一層左右順序倒過來。比如問題中的例子,第三層1-3-6-9經(jīng)過變換后變成了9-6-3-1,順序反過來就對了。 再仔細(xì)觀察一下,對于上面的例子,根節(jié)點(root)的左子節(jié)點及其所有的子孫節(jié)點構(gòu)成根節(jié)點的左子樹(left subtree),同樣的,根節(jié)點(root)的右子節(jié)點及其所有的子孫節(jié)點構(gòu)成根節(jié)點的右子樹(right subtree)。因此翻轉(zhuǎn)一個二叉樹,就是把根節(jié)點的左子樹翻轉(zhuǎn)一下,同樣的把右子樹翻轉(zhuǎn)一下,在交換左右子樹就可以了。左子樹和右子樹
當(dāng)然,翻轉(zhuǎn)左子樹和右子樹的過程和當(dāng)前翻轉(zhuǎn)二叉樹的過程沒有區(qū)別,就是遞歸的調(diào)用當(dāng)前的函數(shù)就可以了。 因此,翻轉(zhuǎn)二叉樹的步驟可總結(jié)如下:
- 翻轉(zhuǎn)根節(jié)點的左子樹(遞歸調(diào)用當(dāng)前函數(shù))
- 翻轉(zhuǎn)根節(jié)點的右子樹(遞歸調(diào)用當(dāng)前函數(shù))
- 交換根節(jié)點的左子節(jié)點與右子節(jié)點
代碼
invertBinaryTree.go
package _226_Invert_Binary_Tree
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func InvertTree(root *TreeNode) *TreeNode {
if nil == root {
return nil
}
if nil != root.Left {
InvertTree(root.Left)
}
if nil != root.Right {
InvertTree(root.Right)
}
root.Left, root.Right = root.Right, root.Left
return root
}
測試代碼
invertBinaryTree_test.go
package _226_Invert_Binary_Tree
import (
"testing"
"fmt"
)
func InitNode(val int, left *TreeNode, right *TreeNode) (ret *TreeNode){
ret = new(TreeNode)
ret.Val = val
ret.Left = left
ret.Right = right
return ret
}
func treeEqual(t1 *TreeNode, t2 *TreeNode) bool{
if t1.Val != t2.Val {
return false
}
if nil == t1.Left && nil != t2.Left {
return false
}else if nil != t1.Left && nil == t2.Left {
return false
} else if nil != t1.Left && nil != t2.Left {
left := treeEqual(t1.Left, t2.Left)
if !left {
return false
}
}
if nil == t1.Right && nil != t2.Right {
return false
}else if nil != t1.Right && nil == t2.Right {
return false
}else if nil != t1.Right && nil != t2.Right {
right := treeEqual(t1.Right, t2.Right)
if !right {
return false
}
}
return true
}
func TreePrint(t1 *TreeNode) {
if nil == t1 {
fmt.Printf("null, ")
return
} else {
fmt.Printf("%+v, ", t1.Val)
}
TreePrint(t1.Left)
TreePrint(t1.Right)
}
func TestInvertTree(t *testing.T) {
l3_1 := InitNode(1, nil, nil)
l3_2 := InitNode(3, nil, nil)
l3_3 := InitNode(6, nil, nil)
l3_4 := InitNode(9, nil, nil)
l2_1 := InitNode(2, l3_1, l3_2)
l2_2 := InitNode(7, l3_3, l3_4)
input := InitNode(4, l2_1, l2_2)
w2_1 := InitNode(7, l3_4, l3_3)
w2_2 := InitNode(2, l3_2, l3_1)
want := InitNode(4, w2_1, w2_2)
ret := InvertTree(input)
equal := treeEqual(want, ret)
TreePrint(want)
fmt.Println()
TreePrint(ret)
fmt.Println()
if equal {
t.Logf("pass")
} else {
t.Errorf("fail, want %+v, get %+v", want, ret)
}
}