一.问题描述
Given a 2D grid
of size n
* m
and an integer k
. You need to shift the grid
k
times.
In one shift operation:
- Element at
grid[i][j]
becomes atgrid[i][j + 1]
. - Element at
grid[i][m - 1]
becomes atgrid[i + 1][0]
. - Element at
grid[n - 1][m - 1]
becomes atgrid[0][0]
.
Return the 2D grid after applying shift operation k
times.
Example 1:
Input: grid
= [[1,2,3],[4,5,6],[7,8,9]], k = 1
Output: [[9,1,2],[3,4,5],[6,7,8]]
Example 2:
Input: grid
= [[3,8,1,9],[19,7,2,5],[4,6,11,10],[12,0,21,13]], k = 4
Output: [[12,0,21,13],[3,8,1,9],[19,7,2,5],[4,6,11,10]]
Example 3:
Input: grid
= [[1,2,3],[4,5,6],[7,8,9]], k = 9
Output: [[1,2,3],[4,5,6],[7,8,9]]
Constraints:
1 <= grid.length <= 50
1 <= grid[i].length <= 50
-1000 <= grid[i][j] <= 1000
0 <= k <= 100
二.解题思路
这道题方法有很多。
1.你可以定义一个单次shift函数然后执行k次shift函数即可。
每次shift函数就是将最后一列移到第一列,然后移动到第一列的最后一列的元素像下移。
因为python原生二维数组没有高级索引,所以只能迭代。
时间复杂度O(kmn)
如果用numpy倒是会简单一点,但是时间复杂度还是那样。
2.可以直接考虑到最后一步,执行了k次shift的数组会成什么样呢
<1 执行k次shift之后哪一列对应哪一列,这好找。
第j列对应j-k%m列,比如你向右移了一次,那么你现在的第二行就是移动前的第一行。
因为python数组支持负索引,比如a[-1]=a[len(a)-1],你可以直接写 res[i][j]=res[i][j-k%m]
因为你想如果只移动一次,那么第一列对应移动前最后一列,正常其他语言你应该写res[i][j]=res[i][m+j-k%m] if j-k%m<0,但是python的话不用。
<2 麻烦一点的就是行的确定,也就是res[i][j]=res[?][j-k%m]中的这个问号。
分析一下知:假如移动了k次,那么所有列至少向下移动了int(k/m)次,比如说数字列数为5,移动5次,相当于所有列都向下移动了一格。
之后要考虑,如果k不能整除m,相当于有些列它的向下移动次数是int(k/m)+1,比如说总共5列,移动6次,当移动5次的时候,相当于原数组全部向下移动一行,最后一行补到第一行,再这种情况下再移动一次,此时最后一列要再向下移动一次。
如果确定这些列?其实就是j-k%m<0的这些需要多移动一次,因为你想这些列的原对应列是不是 是从数组的后面拉到前面来的,而从后面拉倒前面来的全部都要下移。而那些不是从最后一列补过来的只要正常移动就好了。
综上所述,
res[i][j]=grid[i-(int(k/m)+(j-k%m<0))%n][j-k%m]
记得行下移的时候记得%n
3.好像看到有人用了内置的chain函数,之后瞅一眼有时间补上。
PS:如果用numpy的话,高级索引会让这道题变得十分简单,但是本来咱们练leetcode不就是为了打基础吗?
更多leetcode算法题解法: 专栏 leetcode算法从零到结束
三.源码
两个版本,一个容易理解,另一个用列表解析(快一点)
# version 1
class Solution:
def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
n,m=len(grid),len(grid[0])
res=[[0]*m for j in range(n)]
for j in range(m):
for i in range(n):
res[i][j]=grid[i-(int(k/m)+(j-k%m<0))%n][j-k%m]
return res
#version 2
class Solution:
def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
n,m=len(grid),len(grid[0])
res=[grid[i-(int(k/m)+(j-k%m<0))%n][j-k%m] for i in range(n) for j in range(m)]
return [res[i*m:(i+1)*m] for i in range(n)]