這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
從四月份下半月開始,陸陸續續面試了幾家公司,都是golang的崗位。每一次面試,側重點都會有不同,有的會直接給過來一道試題, 然後邊解題,邊講述自己的思路,然後面試官根據你的思路和你交流溝通;有的呢,讓講述自己最近做過的項目,遇到的痛點, 自己怎麼解決的問題思路,而無專屬偶的呢,這樣的面試中,都要需要展示編碼能力。這篇文章就把自己最近面試中遇到的每一個編程問題, 分三步闡述出來:問題描述,解題思路,實際編程。
交替列印數字和字母
問題描述
使用兩個 goroutine 交替列印序列,一個 goroutinue 列印數字, 另外一個goroutine列印字母, 最終效果如下 12AB34CD56EF78GH910IJ 。
解題思路
問題很簡單,使用 channel 來控制列印的進度。使用兩個 channel ,來分別控制數字和字母的列印序列, 數字列印完成後通過 channel 通知字母列印, 字母列印完成後通知數字列印,然後周而復始的工作。
實際編碼<a id="sec-1-3"></a>
runtime.GOMAXPROCS(runtime.NumCPU())chan_n := make(chan bool)chan_c := make(chan bool, 1)done := make(chan struct{})go func() { for i := 1; i < 11; i += 2 { <-chan_c fmt.Print(i) fmt.Print(i + 1) chan_n <- true }}()go func() { char_seq := []string{"A","B","C","D","E","F","G","H","I","J","K"} for i := 0; i < 10; i += 2 { <-chan_n fmt.Print(char_seq[i]) fmt.Print(char_seq[i+1]) chan_c <- true } done <- struct{}{}}()chan_c <- true<-done
代碼執行結果:
12AB34CD56EF78GH910IJ
隨機抽獎<a id="sec-2"></a>
問題描述<a id="sec-2-1"></a>
使用者隨機抽獎,資料結構如下所示:
// map中,key代表名稱,value代表成交單數var users map[string]int64 = map[string]int64{ "a": 10, "b": 6, "c": 3, "d": 12, "f": 1,}
解決思路
從map中選取隨機使用者,拿到這個編碼問題,有點懵逼,但仔細一想,只需把關注使用者的區間,轉變一下資料結構即解題。 把map轉成array,思考起來就簡單多了,原有問題變成了從0至n-1中選取一個數字,數字對應的使用者即中獎使用者。
實際編碼
package mainimport ( "fmt" "math/rand" "time")func GetAwardUserName(users map[string]int64) (name string) { sizeOfUsers := len(users) award_index := rand.Intn(sizeOfUsers) var index int for u_name, _ := range users { if index == award_index { name = u_name return } index += 1 } return}func main() { var users map[string]int64 = map[string]int64{ "a": 10, "b": 6, "c": 3, "d": 12, "e": 20, "f": 1, } rand.Seed(time.Now().Unix()) award_stat := make(map[string]int64) for i := 0; i < 1000; i += 1 { name := GetAwardUserName(users) if count, ok := award_stat[name]; ok { award_stat[name] = count + 1 } else { award_stat[name] = 1 } } for name, count := range award_stat { fmt.Printf("user: %s, award count: %d\n", name, count) } return}
代碼執行結果:
user: f, award count: 178user: d, award count: 152user: b, award count: 159user: e, award count: 182user: c, award count: 170user: a, award count: 159
權重抽獎
問題描述
資料結構和上面一致,只是問題發生變化,需要更加使用者的成單數來抽獎,使用者成單越多,中獎機率越高,結構如下所示:
// map中,key代表名稱,value代表成交單數var users map[string]int64 = map[string]int64{ "a": 10, "b": 6, "c": 3, "d": 12, "f": 1,}
解決思路
這一題是上一題的延伸,加了訂單數進去,做為權重來為使用者抽獎。此題和上面的問題如此的相似,可把上面的問題, 理解成所有的使用者權重都相同的抽獎,而此題是權重不同的抽獎。解決此問題,依舊是把map轉為數組來思考, 把各使用者的權重,從前到後依次拼接到數軸上,數軸的起點到終點即時中獎區間,而隨機數落到的那個使用者的區間,那個使用者即為中獎使用者。
實際編碼<a id="sec-3-3"></a>
package mainimport ( "fmt" "math/rand" "time")func GetAwardUserName(users map[string]int64) (name string) { type A_user struct { Name string Offset int64 Num int64 } a_user_arr := make([]*A_user, 0) var sum_num int64 for name, num := range users { a_user := &A_user{ Name: name, Offset: sum_num, Num: num, } a_user_arr = append(a_user_arr, a_user) sum_num += num } award_num := rand.Int63n(sum_num) for index, _ := range a_user_arr { a_user := a_user_arr[index] if a_user.Offset+a_user.Num > award_num { name = a_user.Name return } } return}func main() { var users map[string]int64 = map[string]int64{ "a": 10, "b": 5, "c": 15, "d": 20, "e": 10, "f": 30, } rand.Seed(time.Now().Unix()) award_stat := make(map[string]int64) for i := 0; i < 10000; i += 1 { name := GetAwardUserName(users) if count, ok := award_stat[name]; ok { award_stat[name] = count + 1 } else { award_stat[name] = 1 } } for name, count := range award_stat { fmt.Printf("user: %s, award count: %d\n", name, count) } return}
代碼執行結果:
user: c, award count: 1667user: f, award count: 3310user: e, award count: 1099user: d, award count: 2276user: b, award count: 549user: a, award count: 1099
總結
問題一來自一家公司 , 側重於語言特性;問題二三來自另外一家公司 ,側重於解決問題的思路;本人更喜歡第二種,很有啟發性。 我之後會把其他自己認為比較有趣的編程任務,整理到此篇文章中,敬請期待。