开心一刻
一次,领导要去精神病院去检查,院长非常紧张,怕病人出什么差错,于是就把病人召集在一起说:“大家都听好了,领导来了,都看我的如果我咳嗽就鼓掌,跺脚就停,如果做的好晚上就给大家吃包子,要是有一个人没做好就谁也别想吃,明白了吗?”大家都点头。
领导来了,大家列队欢迎,这是院长咳嗽了,大家开始鼓掌,领导很高兴边鼓掌边往前走,突然院长跺脚了,掌声立刻停了,这时只有领导还在鼓掌,此时从病人中冲出一人,跑到领导面前就给了他一巴掌,嘴里还念叨说:“你丫不想吃包子啦?”
题目介绍
给定一个大小为 n*m 的矩阵,请以对角线遍历并返回遍历结果。牛客链接
做这道题目的时候遇到了一些感觉不好理解的地方,因此写下这篇博客记录一些心得。
做法
package main
import "fmt"
func diagonalOrder( mat [][]int ) []int {
m, n := len(mat), len(mat[0])
i, j, dir_i, dir_j := 0, 0, -1, 1
var ans = make([]int, m * n)
var idx int
for idx < m * n {
ans[idx] = mat[i][j]
idx++
i, j = i + dir_i, j + dir_j
if i < 0 || j < 0 || i == m || j == n {
if dir_i == 1 {//左下方向
if i < m {
j = 0
} else {
i, j = i - 1, j + 2
}
} else {//右上方向
if j < n {
i = 0
} else {
i, j = i + 2, j - 1
}
}
dir_i, dir_j = dir_j, dir_i
}
}
return ans
}
func main() {
fmt.Println(diagonalOrder([][]int{{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}))
}
算法主要是要能够模仿对角线遍历时方向的改变。我这里用dir_i和dir_j模拟方向,初始化时为-1和1,代表右上方向。最终打印的数组的大小可以确定,因此我直接申请固定大小的数组空间,然后使用idx代表每次填充的数据。每次填充一个数据后,模拟i、j在矩阵中的移动,然后判断是否需要改变方向。
这里需要注意的是14行和20行的代码,往左下方向遍历时,只有遍历最左下角元素后是一种特殊情况,往右上方向遍历时,只有遍历最右上角元素后是一种特殊情况,需要特殊判断。
循环结束的条件为idx < m * n,这个将会导致多计算一次i、j,且肯定是越界的,在本题目中没有问题,但是在下面的扩展题目中将会出现问题。
题目扩展
对角线遍历非标准m*n的矩阵,m、n表示矩阵中最长的行和列。
package main
import "fmt"
func diagonalOrder( mat [][]int ) []int {
m, n := len(mat), 0
count := 0
for i := 0; i < m; i++ {
count += len(mat[i])
if n < len(mat[i]) {
n = len(mat[i])
}
}
i, j, dir_i, dir_j := 0, 0, -1, 1
var ans = make([]int, count)
var idx int
var f = func() {
if i < 0 || j < 0 || i == m || j == n {
if dir_i == 1 {
if i < m {//左下方向
j = 0
} else {
i, j = i-1, j+2
}
} else {
if j < n {//右上方向
i = 0
} else {
i, j = i+2, j-1
}
}
dir_i, dir_j = dir_j, dir_i
}
}
for {
ans[idx] = mat[i][j]
idx++
if idx >= count {
break
}
i, j = i + dir_i, j + dir_j
f()
for j >= len(mat[i]) {
i, j = i + dir_i, j + dir_j
f()
}
}
return ans
}
func main() {
fmt.Println(diagonalOrder([][]int{{1,2,3,4,5,6,7,8,9,0},{5,6,7},{8,9,10,11,12,17,18},{13,14,15,16,2,3,4,5}}))
}
扩展题目中,外循环结束的条件变为用if语句判断idx是否大于等于count,将不会计算多余的那一次i和j的值,否则会造成死循环。
改变方向的判断因为需要使用多次,所以我这里使用了一个内部函数来替换,减少代码行数。
这种非标准的矩阵的对角线遍历其实就是多调用了几次40行和41行的代码,主要就是为了能够找出下一个合法的可访问的位置。
文中都是我个人的理解,如有错误的地方欢迎下方评论告诉我,我及时更正,大家共同进步