写在前面
最近面试了华为go开发,一面中遇到一个算法题,也不是很难,在leetcode上应该属于中等难道。20分钟问问题,40分钟写算法题。
这个算法题最终没有写出来,思路是对的,边界情况考虑有点问题,事后大概花了半个小时才调试处理。
整理一下后发现,其实当时变量定义有点乱,多个地方公用了变量,导致有点绕,边界清空改了这里,那里有出现问题了。其实应该要让自己思路清晰一点,逻辑要再清晰一点,不能公用变量的地方不要公用。
下面来看一下具体的题目
题目:螺旋打印出三角形
输入一个数字n(2<=n<=100),按三角形方向从外向内打印出数字,数字从1开始,同一行数字之间用一个空格隔开。
示例1:
n=2
结果:
1 2
3
示例2:
n=3
结果:
1 2 3
6 4
5
示例3:
n=10
结果:
1 2 3 4 5 6 7 8 9 10
27 28 29 30 31 32 33 34 11
26 45 46 47 48 49 35 12
25 44 54 55 50 36 13
24 43 53 51 37 14
23 42 52 38 15
22 41 39 16
21 40 17
20 18
19
分析
题目意思应该很清楚明了,从示例3中n=10可以发现规律,数字是一层一层、从外向内循环的,而且每层循环都是从对角线开始,如第一层循环从(0,0),第二层循环从(1,1)开始,第三层循环从(2,2)开始,第四层循环从(3,3)开始。因此写代码可以按层开始,写一个循环,每次处理一层数据。
对于每一层,分成3个边,下面先看第一层
- 第一个边,是三角形的行线,从(0,0)开始,向右打印10个数字。
- 第二个边,是三角形的斜线,从(1,8)开始,下左下打印9个数字。
- 第三个边,是三角形的竖线,从(8,0)开始,向上打印9个数字。
至此可以写代码了
代码
func LuoXuanArray(n int) {
idx := 1 // 从1开始递增
// countN 表示每一层三角形单边数据量. 假设n=10,则每层数量为10,7,4,1
countN := n
// 定义结果数组
result := make([][]int, n)
for i := range result {
result[i] = make([]int, n)
}
cycle := 1
for true {
// 处理第 cycle 层
// 1.处理行。1 2 3 4 5 6 7 8 9 10
// (i,j)表示当前行的第一个位置
i := cycle - 1
j := cycle - 1
if i > n/2 || j > n/2 || result[i][j] != 0 {
// 如果某一层开始的数字不等于0或者超过了边界,则可以退出了
break
}
for c := 0; c < countN; c++ {
result[i][j] = idx
j++
idx++
}
// 2.处理斜线,从 (i+1,j-2)开始,需要处理countN-1个数字
// 循环处理countN-1次
i++
j -= 2
for c := 0; c < countN-1; c++ {
result[i][j] = idx
idx++
i++
j--
}
// 3.处理列,从 (i-2,j+1)开始,需要处理countN-2个数字
i -= 2
j++
for c := 1; c <= countN-2; c++ {
result[i][j] = idx
idx++
i--
}
countN -= 3 // 每一层都比上一层的数字少3个
cycle++
}
// 输出结果
for i := range result {
for j := 0; j < n-i; j++ {
fmt.Printf("%d ", result[i][j])
}
fmt.Println()
}
}
难点
这道题有3个点需要注意
- 1.层的数量。作者一开始计算层的数量
level:=(n-1)/2
,用的测试用例是n=3,n=10,这2个是对的,但是当n=2,level=0,显然不对。后面改成从1开始,for循环用true,在循环里面通过i > n/2 || j > n/2 || result[i][j] != 0
判断循环是否需要结束 - 2.对于三条边的处理,开始节点一定要注意
- 行线是从(cycle-1,cycle-1)开始,向右走,并且数量是countN
- 斜线是从行线最后一个节点的基础上,(i+1,j-1)开始的,向左下走,由于在行线处理的for循环中j++了,所以斜线第一个节点是(i+1,j-2),数量是countN-1
- 竖线是从斜线最后一个节点的基础上,(i-1,j)开始,向上走,由于斜线的处理中for循环中i++,j–了,所以竖线第一个节点是(i-2,j++),数量是countN-2 - 3.三个for循环处理三个边的时候,临时变量最好定义成一个单独的,不要用i或者j去遍历。(用i或者j也没问题,但是非常容易出错,代码中出现了很多+1,+2,-1,-2的边界情况,作者就是在这个地方出了问题,导致在规定时间内没有做出来)
leetcode上有个类似的题目:螺旋矩阵,感兴趣的同学可以去做一做,这里是作者写的题解
br>