Gopher面试中的Coding

715001687 7年前
   <p>从四月份下半月开始,陆陆续续面试了几家公司,都是golang的岗位。每一次面试,侧重点都会有不同,有的会直接给过来一道试题, 然后边解题,边讲述自己的思路,然后面试官根据你的思路和你交流沟通;有的呢,让讲述自己最近做过的项目,遇到的难点, 自己怎么解决的问题思路,而无独有偶的呢,这样的面试中,都要需要展示编码能力。这篇文章就把自己最近面试中遇到的每一个编程问题, 分三步阐述出来:问题描述,解题思路,实际编程。</p>    <p>交替打印数字和字母</p>    <h2>问题描述</h2>    <p>使用两个 <code>goroutine</code> 交替打印序列,一个 <code>goroutinue</code> 打印数字, 另外一个goroutine打印字母, 最终效果如下 <em>12AB34CD56EF78GH910IJ</em> 。</p>    <h2>解题思路</h2>    <p>问题很简单,使用 <code>channel</code> 来控制打印的进度。使用两个 <code>channel</code> ,来分别控制数字和字母的打印序列, 数字打印完成后通过 <code>channel</code> 通知字母打印, 字母打印完成后通知数字打印,然后周而复始的工作。</p>    <h2>实际编码</h2>    <pre>  <code class="language-go">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  </code></pre>    <p>代码执行结果:</p>    <pre>  <code class="language-go">12AB34CD56EF78GH910IJ  </code></pre>    <p>随机抽奖</p>    <h2>问题描述</h2>    <p>用户随机抽奖,数据结构如下所示:</p>    <pre>  <code class="language-go">// map中,key代表名称,value代表成交单数  var users map[string]int64 = map[string]int64{    "a": 10,    "b": 6,    "c": 3,    "d": 12,    "f": 1,  }  </code></pre>    <h2>解决思路</h2>    <p>从map中选取随机用户,拿到这个编码问题,有点懵逼,但仔细一想,只需把关注用户的区间,转变一下数据结构即解题。 把map转成array,思考起来就简单多了,原有问题变成了从0至n-1中选取一个数字,数字对应的用户即中奖用户。</p>    <h2>实际编码</h2>    <pre>  <code class="language-go">package main    import (    "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  }  </code></pre>    <p>代码执行结果:</p>    <pre>  <code class="language-go">user: f, award count: 178  user: d, award count: 152  user: b, award count: 159  user: e, award count: 182  user: c, award count: 170  user: a, award count: 159  </code></pre>    <p>权重抽奖</p>    <h2>问题描述</h2>    <p>数据结构和上面一致,只是问题发生变化,需要更加用户的成单数来抽奖,用户成单越多,中奖概率越高,结构如下所示:</p>    <pre>  <code class="language-go">// map中,key代表名称,value代表成交单数  var users map[string]int64 = map[string]int64{    "a": 10,    "b": 6,    "c": 3,    "d": 12,    "f": 1,  }  </code></pre>    <h2>解决思路</h2>    <p>这一题是上一题的延伸,加了订单数进去,做为权重来为用户抽奖。此题和上面的问题如此的相似,可把上面的问题, 理解成所有的用户权重都相同的抽奖,而此题是权重不同的抽奖。解决此问题,依旧是把map转为数组来思考, 把各用户的权重,从前到后依次拼接到数轴上,数轴的起点到终点即时中奖区间,而随机数落到的那个用户的区间,那个用户即为中奖用户。</p>    <h2>实际编码</h2>    <pre>  <code class="language-go">package main    import (    "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  }  </code></pre>    <p>代码执行结果:</p>    <pre>  <code class="language-go">user: c, award count: 1667  user: f, award count: 3310  user: e, award count: 1099  user: d, award count: 2276  user: b, award count: 549  user: a, award count: 1099  </code></pre>    <h2>总结</h2>    <p>问题一来自一家公司 , 侧重于语言特性;问题二三来自另外一家公司 ,侧重于解决问题的思路;本人更喜欢第二种,很有启发性。 我之后会把其他自己认为比较有趣的编程任务,整理到此篇文章中,敬请期待。</p>    <p><br> <br> 来自:http://www.jianshu.com/p/268068e786b8</p>