年初找工做时,面过一家自称区块链行业前三的公司(事实上也差很少),他们笔试题蛮有意思的,时隔半年,估计他们也更新题库了,就拿出来和你们分享一下。html
翻译以下:面试
Sandy是一个制做地图的探险家。她从点(0,0)开始探索,每次能够向左、向右、向上或者向下移动一点。例如,若是Sandy站在(x,y)处,她能够移动到(x+1,y),(x-1,y),(x,y+1)或(x,y-1)。她不能跳也不能走对角线方向。算法
John要阻止Sandy,他会在坐标数字的绝对值之和大于21的地方埋地雷。例如,点(59,-79)有地雷,由于5+7+9+9>21;而点(-113,-104)没有地雷,由于1+1+3+1+0+4<=21。bash
若是Sandy踩到地雷,她会死。她不能跳过地雷,必须绕着走。app
请编写一个程序,来计算Sandy从(0,0)开始能够访问的点的数量。echarts
首先,能够快速判断出这道题考的是图的遍历,遍历的方法无非深度优先,或者广度优先。此题是要计算全部可遍历的点,因而,我选择用广度优先。ide
而后,由于Sandy能够向四个方向移动,初步能够判断能够遍历的范围是关于XY轴对称。再则,根据地雷的埋放规则“坐标数字的绝对值之和大于21的地方埋地雷”, 能够进一步推出能够遍历的范围是关于y=x、y=-x、y=0和x=0对称的。举个例子,(56,65),(-56,65),(56,-65),(-56,-65)和(65,56),(-65,56),(65,-56),(-65,-56)都是埋放的地雷的点。函数
因而,咱们只须要考虑x>=0,y>=0且x<=y的区域,乘以对称的次数,就能够推出全部能够遍历的点。但须要注意的是对于x>0,y>0且x<y的区域,能够访问点能够乘以8;对于x>0和y=x且x>0这两条边,只须要乘以4就好,由于它们是被两个区块所共有的,乘以8就算重了;特别须要注意的是(x=0,y=0)这点,是全部能够遍历的区域的中心,乘以1便可。区块链
按照上述的分析,编码工做就能够依次开始了。ui
首先,先定义一个关于的点的结构体,并增长一个计算坐标和的函数。
type Point struct {
X int
Y int
}
func (p Point) CoordinateSum() int {
xNumStrs := strings.Split(strconv.Itoa(p.X), "")
yNumStrs := strings.Split(strconv.Itoa(p.Y), "")
numStrs := append(xNumStrs, yNumStrs...)
sum := 0
for _, str := range numStrs {
num, _ := strconv.ParseInt(str, 10, 32)
sum += int(num)
}
return sum
}
复制代码
CoordinateSum不会改变点的X,Y值,因而,定义和值类型的方法。
接着,在通用的遍历图算法,须要有个map判断当前点是否遍历过,来剪枝。在本题中,还须要判断当前点是不是地雷,因而,我把这两段逻辑写到了一方法里。
var checkedPoints map[Point]bool
func CheckPoint(p Point) bool {
if _, ok := checkedPoints[p]; ok {
return false
}
if p.Y > p.X || p.X < 0 || p.Y < 0{
return false
}
return p.CoordinateSum() <= 21
}
复制代码
全局变量在工程化的代码中是须要尽可能避免使用的,这里图方便,权且用一下。
下面就是广度优先遍历的代码了。
var toCheckPoints = list.New()
checkedPoints = map[Point]bool{}
var point = Point{0, 0}
toCheckPoints.PushFront(point)
checkedPoints[point] = true
for toCheckPoints.Len() > 0 {
element := toCheckPoints.Front()
point = toCheckPoints.Remove(element).(Point)
searchPoint := Point{point.X, point.Y - 1}
Search(searchPoint, toCheckPoints)
searchPoint = Point{point.X - 1, point.Y}
Search(searchPoint, toCheckPoints)
searchPoint = Point{point.X + 1, point.Y}
Search(searchPoint, toCheckPoints)
searchPoint = Point{point.X, point.Y + 1}
Search(searchPoint, toCheckPoints)
}
func Search(searchPoint Point, toCheckPoints *list.List) {
if CheckPoint(searchPoint) {
checkedPoints[searchPoint] = true
toCheckPoints.PushFront(searchPoint)
} else {
if _, ok := checkedPoints[searchPoint]; !ok {
checkedPoints[searchPoint] = false
}
}
}
复制代码
最后,就是根据遍历的过的点,计算能够遍历点的数量。
pointsOnMap := 0
var minedPoints = list.New()
var visiblePoints = list.New()
for point, visible := range checkedPoints {
if visible {
if point.X == 0 && point.Y == 0 {
pointsOnMap += 1
} else if point.Y == 0 || point.X == point.Y {
pointsOnMap += 4
} else {
pointsOnMap += 8
}
visiblePoints.PushFront(point)
}else {
minedPoints.PushFront(point)
}
}
fmt.Println("Points on map are", pointsOnMap)
复制代码
程序写好,可是不肯定对不对怎么办?
这个吗,就须要把能够遍历的点和地雷分别画出来,就能够知道。
这里,我选择了用Echarts的散点图的在线示例来画。地址是echarts.baidu.com/examples/ed…
使用的配置是:
option = {
dataZoom: [
{
type: 'slider',
show: true,
xAxisIndex: [0],
start: 0,
end: 500,
},
{
type: 'slider',
show: true,
yAxisIndex: [0],
start: 0,
end: 250
}
],
xAxis: {},
yAxis: {},
series: [{
symbolSize: 1,
data: [
[10.0, 8.04],
],
type: 'scatter'
}]
};
复制代码
用算出来的点,替换data部分就能够画出来了。
能够遍历的点的图是:
package main
import (
"container/list"
"fmt"
"strconv"
"strings"
)
type Point struct {
X int
Y int
}
func (p Point) CoordinateSum() int {
xNumStrs := strings.Split(strconv.Itoa(p.X), "")
yNumStrs := strings.Split(strconv.Itoa(p.Y), "")
numStrs := append(xNumStrs, yNumStrs...)
sum := 0
for _, str := range numStrs {
num, _ := strconv.ParseInt(str, 10, 32)
sum += int(num)
}
return sum
}
var checkedPoints map[Point]bool
func main() {
var toCheckPoints = list.New()
checkedPoints = map[Point]bool{}
var point = Point{0, 0}
toCheckPoints.PushFront(point)
checkedPoints[point] = true
for toCheckPoints.Len() > 0 {
element := toCheckPoints.Front()
point = toCheckPoints.Remove(element).(Point)
searchPoint := Point{point.X, point.Y - 1}
Search(searchPoint, toCheckPoints)
searchPoint = Point{point.X - 1, point.Y}
Search(searchPoint, toCheckPoints)
searchPoint = Point{point.X + 1, point.Y}
Search(searchPoint, toCheckPoints)
searchPoint = Point{point.X, point.Y + 1}
Search(searchPoint, toCheckPoints)
}
//fmt.Println(len(checkedPoints))
//fmt.Println(checkedPoints)
pointsOnMap := 0
var minedPoints = list.New()
var visiblePoints = list.New()
for point, visible := range checkedPoints {
if visible {
if point.X == 0 && point.Y == 0 {
pointsOnMap += 1
} else if point.Y == 0 || point.X == point.Y {
pointsOnMap += 4
} else {
pointsOnMap += 8
}
visiblePoints.PushFront(point)
}else {
minedPoints.PushFront(point)
}
}
fmt.Println("Points on map are", pointsOnMap)
//for e := minedPoints.Front(); e != nil; e = e.Next() {
// p := e.Value.(Point)
// fmt.Println("[", p.X, ",", p.Y,"],")
//}
}
func Search(searchPoint Point, toCheckPoints *list.List) {
if CheckPoint(searchPoint) {
checkedPoints[searchPoint] = true
toCheckPoints.PushFront(searchPoint)
} else {
if _, ok := checkedPoints[searchPoint]; !ok {
checkedPoints[searchPoint] = false
}
}
}
func CheckPoint(p Point) bool {
if _, ok := checkedPoints[p]; ok {
return false
}
if p.Y > p.X || p.X < 0 || p.Y < 0{
return false
}
return p.CoordinateSum() <= 21
}
复制代码
答案:287881
笔试我是答对了,可是也没能获得面试机会……
HR反馈说,面试官以为个人年龄和实力不符合团队结构的指望 ˚‧º·(˚ ˃̣̣̥⌓˂̣̣̥ )‧º·˚
那次面试,也最终断了我继续在区块链行业奋斗的但愿。没办法,我但是要工做养家的男人哈。