You are given an m x n matrix of characters boxGrid representing a side-view of a box. Each cell of the box is one of the following:
'#''*''.'The box is rotated 90 degrees clockwise, causing some of the stones to fall due to gravity. Each stone falls down until it lands on an obstacle, another stone, or the bottom of the box. Gravity does not affect the obstacles' positions, and the inertia from the box's rotation does not affect the stones' horizontal positions.
It is guaranteed that each stone in boxGrid rests on an obstacle, another stone, or the bottom of the box.
Return an n x m matrix representing the box after the rotation described above.
Example 1:
Input: boxGrid = [
["#",".","*","."],
["#","#","*","."]
]
Output: [
["#","."],
["#","#"],
["*","*"],
[".","."]
]Example 2:
Input: boxGrid = [
["#","#","*",".","*","."],
["#","#","#","*",".","."],
["#","#","#",".","#","."]
]
Output: [
[".","#","#"],
[".","#","#"],
["#","#","*"],
["#","*","."],
["#",".","*"],
["#",".","."]
]Constraints:
m == boxGrid.lengthn == boxGrid[i].length1 <= m, n <= 500boxGrid[i][j] is either '#', '*', or '.'.Before attempting this problem, you should be comfortable with:
When the box is rotated 90 degrees clockwise, gravity pulls stones downward in the new orientation. Before rotation, rows become columns, so stones in each row should fall to the right (toward the end of the row). We simulate gravity by moving each stone as far right as possible until it hits another stone, an obstacle, or the boundary. After simulating gravity, we perform the rotation by transposing and reversing the row order.
# is found, scan rightward to find the farthest empty cell . before hitting an obstacle * or boundary.grid:grid has COLS rows and ROWS columns.c in the original grid, the new row at index c contains elements from bottom to top of that column.grid.class Solution:
def rotateTheBox(self, boxGrid: List[List[str]]) -> List[List[str]]:
ROWS, COLS = len(boxGrid), len(boxGrid[0])
for r in range(ROWS - 1, -1, -1):
for c1 in range(COLS - 1, -1, -1):
if boxGrid[r][c1] == '#':
c2 = c1 + 1
while c2 < COLS and boxGrid[r][c2] == '.':
c2 += 1
boxGrid[r][c1] = '.'
boxGrid[r][c2 - 1] = '#'
res = []
for c in range(COLS):
col = []
for r in range(ROWS - 1, -1, -1):
col.append(boxGrid[r][c])
res.append(col)
return resWhere is the number of rows and is the number of columns.
Instead of scanning rightward for each stone, we can use a two-pointer technique. Maintain a pointer i that tracks the rightmost available position for a stone. Scan from right to left: when we see a stone, swap it with position i and decrement i. When we see an obstacle, reset i to just before the obstacle. This avoids redundant scanning and processes each cell at most twice.
i to COLS - 1 (rightmost position).#, swap it with position i, then decrement i.*, reset i to c - 1 (just before the obstacle).grid by mapping each column of the original to a row in the result (reading bottom to top).grid.class Solution:
def rotateTheBox(self, boxGrid: List[List[str]]) -> List[List[str]]:
ROWS, COLS = len(boxGrid), len(boxGrid[0])
for r in range(ROWS):
i = COLS - 1
for c in reversed(range(COLS)):
if boxGrid[r][c] == "#":
boxGrid[r][c], boxGrid[r][i] = boxGrid[r][i], boxGrid[r][c]
i -= 1
elif boxGrid[r][c] == "*":
i = c - 1
res = []
for c in range(COLS):
col = [] # this is a row after rotation
for r in reversed(range(ROWS)):
col.append(boxGrid[r][c])
res.append(col)
return resWhere is the number of rows and is the number of columns.
We can combine the gravity simulation and rotation into a single pass. Instead of modifying the original grid and then rotating, we directly write stones and obstacles to their final positions in the rotated result grid. This eliminates the need to modify the input and performs both operations simultaneously.
grid of size COLS x ROWS, filled with empty cells ..grid, initialize pointer i to COLS - 1.#, place it at the rotated position corresponding to i, then decrement i.*, place it at its rotated position and reset i to c - 1.(r, c) is (c, ROWS - r - 1) for obstacles, and (i, ROWS - r - 1) for stones.grid.class Solution:
def rotateTheBox(self, boxGrid: List[List[str]]) -> List[List[str]]:
ROWS, COLS = len(boxGrid), len(boxGrid[0])
res = [["."] * ROWS for _ in range(COLS)]
for r in range(ROWS):
i = COLS - 1
for c in reversed(range(COLS)):
if boxGrid[r][c] == "#":
res[i][ROWS - r - 1] = "#"
i -= 1
elif boxGrid[r][c] == "*":
res[c][ROWS - r - 1] = "*"
i = c - 1
return resWhere is the number of rows and is the number of columns.
After rotation, gravity pulls stones downward, but before rotation stones should fall to the right (toward higher column indices). Processing stones left-to-right instead of right-to-left causes stones to fall incorrectly, as earlier stones block the path for later ones.
When an obstacle * is encountered, the drop position pointer must reset to just before the obstacle (c - 1). Failing to reset this pointer causes stones to incorrectly pass through or stack on top of obstacles.
The rotation transforms position (r, c) to (c, ROWS - 1 - r) for a 90-degree clockwise rotation. Using incorrect formulas like (c, r) or (ROWS - 1 - r, c) results in a transposed or incorrectly flipped matrix instead of a proper rotation.