Go语言解决LeetCode 1260:二维网格迁移算法解析
LeetCode 1260题要求将m*n的二维网格进行k次循环迁移。核心难点在于高效模拟k次移动而不产生大量重复计算。通过将二维坐标映射为一维数组,利用取模运算确定有效步数,并根据k值与总长度一半的关系选择向左或向右平移,可一次性完成所有元素的重新排列,显著降低时间复杂度。
题目核心逻辑
题目给出的迁移规则定义了元素在网格中的流动路径:grid[i][j] 移至 grid[i][j+1];当到达行尾时,移至下一行首 grid[i+1][0];若到达右下角 grid[m-1][n-1],则回到左上角 grid[0][0]。
这种连续不断的线性位移可以看作是一个环形队列的旋转。若直接将此过程模拟为k次独立的矩阵遍历,在k较大时效率极低。
第1步:理解数据映射关系
观察迁移路径可知,整个二维网格实际上是一个被展开的一维线性序列。对于任意元素 grid[i][j],它在展开后的一维数组中的索引为 i * n + j。
因此,问题转化为:在一个长度为 m * n 的一维数组中,将其元素整体向右循环移动 k 位,最后再还原回二维结构。
以示例1为例,输入
grid = [[1,2,3],[4,5,6],[7,8,9]], k = 1。
展开为一维:[1,2,3,4,5,6,7,8,9]。
向右移动1位后变为:[9,1,2,3,4,5,6,7,8]。
再还原为二维即为输出结果。
算法优化思路
直接模拟每次迁移不仅速度慢,还容易出错。我们可以采用“一次到位”的策略,但需处理两个关键优化点:
- 取模简化步数:网格总长度为
L = m * n。移动L次等同于原位置不动。因此,实际有效移动步数为k % L。 - 左右移动方向选择:当
k % L较大时(超过总长的一半),向右循环移动的效率低于向左移动。例如总长9,k=8。向右移8步等价于向左移1步。比较k_remainder与L/2,若前者大,则转换为向左移动L - k_remainder步,通常能减少部分内存拷贝操作的复杂性。
Go语言代码实现
以下实现采用了空间换时间的策略:先展平数组,调整后再重塑。虽然使用了额外的一维临时数组(长度与原网格相同),但避免了频繁创建切片或多次遍历矩阵。
func shiftGrid(grid [][]int, k int) [][]int {
m := len(grid)
n := len(grid[0])
total := m * n
// 1. 提取扁平化数组
flat := make([]int, total)
idx := 0
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
flat[idx] = grid[i][j]
idx++
}
}
// 2. 处理有效步数
step := k % total
if step == 0 {
return grid // 不需要移动
}
// 3. 决定移动方向以减少操作量
res := make([]int, total)
if step < total/2 {
// 向右移 step 位:尾部取 step 个放到最前面
// 后半段 (total-step ~ total-1) -> 前部 (0 ~ step-1)
copy(res[:step], flat[total-step:])
// 前半段 (0 ~ total-step-1) -> 后部 (step ~ total-1)
copy(res[step:], flat[:total-step])
} else {
// 相当于向左移 total-step 位:头部取 step 个放到最后面
leftStep := total - step
// 前半段 (0 ~ leftStep-1) -> 尾部 (step ~ total-1)
copy(res[step:], flat[:leftStep])
// 后半段 (leftStep ~ total-1) -> 前部 (0 ~ step-1)
copy(res[:step], flat[leftStep:])
}
// 4. 重塑为二维网格
result := make([][]int, m)
for i := 0; i < m; i++ {
result[i] = make([]int, n)
for j := 0; j < n; j++ {
result[i][j] = res[i*n+j]
}
}
return result
}
代码关键点解析
copy`函数的使用:Go标准库的copy`函数非常高效,可以直接处理切片重叠或不重叠的数据移动,比手动遍历赋值更快且不易出错。direction logic`逻辑:通过if/else分支分别处理“末尾向前挪”和“首部向后挪”,保证了无论k大小,都只需两次主要的内存拷贝操作。
复杂度分析
- 时间复杂度:
O(m*n)。我们需要遍历所有元素进行展平和重塑各一次,中间拷贝也是线性的。 - 空间复杂度:
O(m*n)。用于存储扁平化后的数组及最终结果。这在LeetCode等在线判题环境中是完全可接受的。
测试验证
我们对比几种边界情况:
- k = 0:不移动,返回原数组。
- k = m*n:取模后为0,同样不移动。
- 非方阵:如2x4网格,算法依然依靠总长度进行统一计算,无需特殊处理维度差异。
示例2:4行4列,共16个元素。k=4时,向右移动4位,即前两列移动到后两列之后,验证代码输出是否正确匹配预期。
以上就是Go语言解决LeetCode 1260:二维网格迁移算法解析的详细内容,更多关于Go语言二维网格迁移的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













