
Go 中对二维切片进行原地转置时,若使用双重循环从 j = 0 开始交换 a[i][j] 和 a[j][i],会导致每对元素被交换两次(即还原),最终矩阵不变;正确做法是仅遍历上三角区域(j 从 i+1 开始),避免重复交换。
go 中对二维切片进行原地转置时,若使用双重循环从 `j = 0` 开始交换 `a[i][j]` 和 `a[j][i]`,会导致每对元素被交换两次(即还原),最终矩阵不变;正确做法是仅遍历上三角区域(`j` 从 `i+1` 开始),避免重复交换。
在 Go 中实现方阵(square matrix)的转置时,一个常见误区是直接套用“对称交换”逻辑却忽略索引范围,导致结果未发生变化。问题核心在于:原地转置必须确保每对对角线对称位置的元素仅交换一次;而原始代码中内层循环 j 从 0 开始,使得当 i ≠ j 时,(i,j) 和 (j,i) 会在不同轮次中被分别处理两次——例如 (0,1) 处的交换会在 i=0,j=1 时发生,而 (1,0) 又会在 i=1,j=0 时再次触发,等价于两次赋值,最终抵消。
✅ 正确的原地转置应只遍历严格上三角区域(即 j > i),跳过主对角线(i == j 无需交换)和下三角(由上三角覆盖)。以下是推荐实现:
func Transpose(a [][]bool) {
n := len(a)
for i := 0; i < n; i++ {
for j := i + 1; j < n; j++ {
a[i][j], a[j][i] = a[j][i], a[i][j]
}
}
}该实现时间复杂度为 O(n²/2),空间复杂度为 O(1),真正实现了原地操作。注意:此函数要求输入为规则方阵(即所有 a[i] 长度均为 n),否则 a[j][i] 可能越界 panic。
⚠️ 补充说明:
- Go 的切片是引用类型,但 [][]bool 是切片的切片:外层切片头包含指向子切片头的指针数组,内层切片各自管理自己的底层数组。因此 a[i][j] 的赋值是直接修改底层数组元素,无需额外解引用。
- 若需支持非方阵或避免修改原数据,应采用创建新矩阵的方式(如答案中 b := make([][]bool, n) 的方案),再通过 copy(a, b) 浅拷贝外层切片头——但注意 copy 仅复制切片头(长度、容量、数据指针),不深拷贝内层底层数组;若需完全独立副本,须逐行 make 并 copy。
最后,务必在调用前校验矩阵有效性:
func Transpose(a [][]bool) {
if len(a) == 0 {
return
}
n := len(a)
for i := range a {
if len(a[i]) != n {
panic("Transpose: input is not a square matrix")
}
}
for i := 0; i < n; i++ {
for j := i + 1; j < n; j++ {
a[i][j], a[j][i] = a[j][i], a[i][j]
}
}
}这样既保证健壮性,又维持了高效原地转置的核心优势。


















