1260. Shift 2D Grid - Explanation
Description
Shift the rectangular matrix grid to the right k times and return the resulting matrix. During each shift, every value moves one column to the right. A value leaving the last column moves to the first column of the next row; the bottom-right value wraps around to the top-left cell. All moves within one shift happen simultaneously.
Example 1:
Input: grid = [[1,2],[3,4]]
k = 1
Output: [[4,1],[2,3]]Explanation: The values 1 and 3 move right, 2 moves to the start of the next row, and 4 wraps to the top-left corner. The resulting rows are [4, 1] and [2, 3].
Example 2:
Input: grid = [[5,6,7]]
k = 2
Output: [[6,7,5]]Explanation: After one shift the row is [7, 5, 6]. A second shift produces [6, 7, 5].
Example 3:
Input: grid = [[8],[9]]
k = 0
Output: [[8],[9]]Explanation: Zero shifts leave both cells in their original positions, so the matrix is unchanged.
Constraints:
gridis rectangular, with between1and50rows and between1and50columns.-1000 <= grid[i][j] <= 10000 <= k <= 100
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- 2D Arrays / Matrices - Traversing and manipulating elements using row and column indices
- Array Rotation - Understanding how elements shift positions in a circular manner
- Index Mapping - Converting between 2D coordinates (row, column) and 1D linear indices
- Modular Arithmetic - Using modulo to handle wrap-around when positions exceed array bounds
1. Simulation (Extra Space)
Intuition
Shifting a 2D grid is like rotating all elements forward by one position. Each element moves to the next column, and elements at the end of a row wrap around to the start of the next row. The last element of the grid wraps to position (0, 0).
By simulating this process k times, we can achieve the desired result. For each shift, we copy each element to its new position in a fresh grid.
Algorithm
- For each shift iteration (k times):
- Create a new grid
curfilled with zeros. - Copy each element from column
cto columnc + 1in the same row. - Handle the last column separately: element at
(r, n-1)wraps to((r + 1) % m, 0). - Replace the original grid with
cur.
- Create a new grid
- Return the final grid after all shifts.
class Solution:
def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
m, n = len(grid), len(grid[0])
while k:
cur = [[0] * n for _ in range(m)]
for r in range(m):
for c in range(n - 1):
cur[r][c + 1] = grid[r][c]
for r in range(m):
cur[(r + 1) % m][0] = grid[r][n - 1]
grid = cur
k -= 1
return gridTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the number of rows in the grid, is the number of columns in the grid, and is the shift count.
2. Simulation
Intuition
Instead of creating a new grid each time, we can shift elements in place. The key insight is that shifting works like a rotation: each element takes the place of the previous one. By keeping track of the last element (which wraps to the first position), we can propagate values through the entire grid in a single pass.
Algorithm
- For each shift iteration (k times):
- Store the last element
grid[m-1][n-1]asprev. - Traverse the grid row by row, column by column.
- At each cell, swap the current element with
prev. - This naturally propagates each element to the next position.
- Store the last element
- Return the grid after all shifts.
Time & Space Complexity
- Time complexity:
- Space complexity: for the output matrix.
Where is the number of rows in the grid, is the number of columns in the grid, and is the shift count.
3. Convert to One Dimensional Array
Intuition
A 2D grid can be viewed as a 1D array if we flatten it row by row. Shifting in a 1D array is simply rotating elements to the right. The classic way to rotate an array by k positions is to use three reversals: reverse the entire array, then reverse the first k elements, then reverse the remaining elements.
Algorithm
- Flatten the 2D grid into a 1D array
arrwherearr[r * n + c] = grid[r][c]. - Reduce
kby takingk % N(whereN = m * n) to avoid unnecessary full rotations. - Reverse the entire array.
- Reverse the first
kelements. - Reverse the remaining elements from index
ktoN-1. - Map the 1D array back to the 2D grid.
- Return the result.
class Solution:
def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
m, n = len(grid), len(grid[0])
N = m * n
k %= N
arr = [0] * N
for r in range(m):
for c in range(n):
arr[r * n + c] = grid[r][c]
def reverse(l, r):
while l < r:
arr[l], arr[r] = arr[r], arr[l]
l += 1
r -= 1
reverse(0, N - 1)
reverse(0, k - 1)
reverse(k, N - 1)
for r in range(m):
for c in range(n):
grid[r][c] = arr[r * n + c]
return gridTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the number of rows in the grid and is the number of columns in the grid.
4. Iteration
Intuition
Instead of actually shifting elements, we can compute where each element should go after k shifts. The position of an element in a flattened grid is r * n + c. After k shifts, this becomes (r * n + c + k) % (m * n). We can then convert this back to 2D coordinates.
This approach processes each element exactly once, computing its final position directly.
Algorithm
- Create a result grid of the same dimensions.
- For each cell
(r, c):- Compute the new flattened position:
newVal = (r * n + c + k) % (m * n). - Convert back to 2D:
newR = newVal / n,newC = newVal % n. - Place the original value at the new position:
res[newR][newC] = grid[r][c].
- Compute the new flattened position:
- Return the result grid.
class Solution:
def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
M, N = len(grid), len(grid[0])
def posToVal(r, c):
return r * N + c
def valToPos(v):
return [v // N, v % N]
res = [[0] * N for _ in range(M)]
for r in range(M):
for c in range(N):
newVal = (posToVal(r, c) + k) % (M * N)
newR, newC = valToPos(newVal)
res[newR][newC] = grid[r][c]
return resTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the number of rows in the grid and is the number of columns in the grid.
Common Pitfalls
Not Reducing k Modulo Total Elements
When k is larger than the total number of elements (m * n), performing k shifts is redundant since the grid returns to its original state after every m * n shifts. Failing to reduce k with modulo leads to unnecessary iterations and potential timeout errors.
Incorrect 2D to 1D Index Conversion
When flattening the grid or computing new positions, using incorrect formulas for converting between 2D coordinates (r, c) and 1D index causes elements to be placed in wrong positions. The correct formulas are: index = r * n + c and r = index / n, c = index % n.
Sign in to join the discussion