Skip to content

Commit 825fe2b

Browse files
committed
Rotating the box
1 parent fc075a6 commit 825fe2b

File tree

2 files changed

+299
-0
lines changed

2 files changed

+299
-0
lines changed

1861.rotating_the_box/box.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# 1861. Rotating the box
2+
# Topics: 'Matrix', 'Array', 'Two Pointers'
3+
# Level: 'Medium'
4+
5+
# 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:
6+
7+
# A stone '#'
8+
# A stationary obstacle '*'
9+
# Empty '.'
10+
11+
# 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.
12+
13+
# It is guaranteed that each stone in boxGrid rests on an obstacle, another stone, or the bottom of the box.
14+
15+
# Return an n x m matrix representing the box after the rotation described above.
16+
17+
18+
19+
# Example 1:
20+
21+
# Input: boxGrid = [["#",".","#"]]
22+
# Output: [["."],
23+
# ["#"],
24+
# ["#"]]
25+
26+
# Example 2:
27+
28+
# Input: boxGrid = [["#",".","*","."],
29+
# ["#","#","*","."]]
30+
# Output: [["#","."],
31+
# ["#","#"],
32+
# ["*","*"],
33+
# [".","."]]
34+
35+
# Example 3:
36+
37+
# Input: boxGrid = [["#","#","*",".","*","."],
38+
# ["#","#","#","*",".","."],
39+
# ["#","#","#",".","#","."]]
40+
# Output: [[".","#","#"],
41+
# [".","#","#"],
42+
# ["#","#","*"],
43+
# ["#","*","."],
44+
# ["#",".","*"],
45+
# ["#",".","."]]
46+
47+
48+
49+
# Constraints:
50+
51+
# m == boxGrid.length
52+
# n == boxGrid[i].length
53+
# 1 <= m, n <= 500
54+
# boxGrid[i][j] is either '#', '*', or '.'.
55+
56+
from typing import List
57+
58+
class Solution:
59+
def rotateTheBox(self, grid: List[List[str]]) -> List[List[str]]:
60+
ROWS, COLS = len(grid), len(grid[0])
61+
62+
for i in range(ROWS):
63+
R = L = COLS-1
64+
while True:
65+
if L < 0:
66+
break
67+
if grid[i][L] == '.':
68+
L-=1
69+
continue
70+
if grid[i][L] == '*':
71+
L-=1
72+
R = L
73+
continue
74+
grid[i][L], grid[i][R] = grid[i][R], grid[i][L]
75+
L-=1
76+
R-=1
77+
78+
res = []
79+
for c in range (len(grid[0])):
80+
col = []
81+
for r in range (len(grid)-1, -1, -1):
82+
col.append(grid[r][c])
83+
res.append(col)
84+
85+
return res

1861.rotating_the_box/test_box.py

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
import unittest
2+
from typing import List
3+
from box import Solution
4+
5+
6+
class TestRotateTheBox(unittest.TestCase):
7+
8+
def setUp(self):
9+
self.solution = Solution()
10+
11+
def test_example_1_single_row(self):
12+
"""Test with single row, basic gravity"""
13+
grid = [["#", ".", "#"]]
14+
expected = [
15+
["."],
16+
["#"],
17+
["#"]
18+
]
19+
result = self.solution.rotateTheBox(grid)
20+
self.assertEqual(result, expected)
21+
22+
def test_example_2_with_obstacles(self):
23+
"""Test with obstacles blocking stones"""
24+
grid = [
25+
["#", ".", "*", "."],
26+
["#", "#", "*", "."]
27+
]
28+
expected = [
29+
["#", "."],
30+
["#", "#"],
31+
["*", "*"],
32+
[".", "."]
33+
]
34+
result = self.solution.rotateTheBox(grid)
35+
self.assertEqual(result, expected)
36+
37+
def test_example_3_larger_grid(self):
38+
"""Test with larger grid and multiple obstacles"""
39+
grid = [
40+
["#", "#", "*", ".", "*", "."],
41+
["#", "#", "#", "*", ".", "."],
42+
["#", "#", "#", ".", "#", "."]
43+
]
44+
expected = [
45+
[".", "#", "#"],
46+
[".", "#", "#"],
47+
["#", "#", "*"],
48+
["#", "*", "."],
49+
["#", ".", "*"],
50+
["#", ".", "."]
51+
]
52+
result = self.solution.rotateTheBox(grid)
53+
self.assertEqual(result, expected)
54+
55+
def test_all_empty(self):
56+
"""Test with all empty cells"""
57+
grid = [
58+
[".", ".", "."],
59+
[".", ".", "."]
60+
]
61+
expected = [
62+
[".", "."],
63+
[".", "."],
64+
[".", "."]
65+
]
66+
result = self.solution.rotateTheBox(grid)
67+
self.assertEqual(result, expected)
68+
69+
def test_all_stones(self):
70+
"""Test with all stones"""
71+
grid = [
72+
["#", "#", "#"],
73+
["#", "#", "#"]
74+
]
75+
expected = [
76+
["#", "#"],
77+
["#", "#"],
78+
["#", "#"]
79+
]
80+
result = self.solution.rotateTheBox(grid)
81+
self.assertEqual(result, expected)
82+
83+
def test_all_obstacles(self):
84+
"""Test with all obstacles"""
85+
grid = [
86+
["*", "*", "*"],
87+
["*", "*", "*"]
88+
]
89+
expected = [
90+
["*", "*"],
91+
["*", "*"],
92+
["*", "*"]
93+
]
94+
result = self.solution.rotateTheBox(grid)
95+
self.assertEqual(result, expected)
96+
97+
def test_single_cell_stone(self):
98+
"""Test with single cell containing a stone"""
99+
grid = [["#"]]
100+
expected = [["#"]]
101+
result = self.solution.rotateTheBox(grid)
102+
self.assertEqual(result, expected)
103+
104+
def test_single_cell_empty(self):
105+
"""Test with single cell that's empty"""
106+
grid = [["."]]
107+
expected = [["."]]
108+
result = self.solution.rotateTheBox(grid)
109+
self.assertEqual(result, expected)
110+
111+
def test_single_cell_obstacle(self):
112+
"""Test with single cell obstacle"""
113+
grid = [["*"]]
114+
expected = [["*"]]
115+
result = self.solution.rotateTheBox(grid)
116+
self.assertEqual(result, expected)
117+
118+
def test_stones_already_at_bottom(self):
119+
"""Test where stones are already in final position"""
120+
grid = [
121+
[".", ".", "#"],
122+
[".", ".", "#"]
123+
]
124+
expected = [
125+
[".", "."],
126+
[".", "."],
127+
["#", "#"]
128+
]
129+
result = self.solution.rotateTheBox(grid)
130+
self.assertEqual(result, expected)
131+
132+
def test_multiple_obstacles_in_row(self):
133+
"""Test with multiple obstacles creating compartments"""
134+
grid = [["#", "*", "#", "*", "#"]]
135+
expected = [
136+
["#"],
137+
["*"],
138+
["#"],
139+
["*"],
140+
["#"]
141+
]
142+
result = self.solution.rotateTheBox(grid)
143+
self.assertEqual(result, expected)
144+
145+
def test_stones_separated_by_empty(self):
146+
"""Test stones with empty spaces between them"""
147+
grid = [["#", ".", ".", "#", ".", "#"]]
148+
expected = [
149+
["."],
150+
["."],
151+
["."],
152+
["#"],
153+
["#"],
154+
["#"]
155+
]
156+
result = self.solution.rotateTheBox(grid)
157+
self.assertEqual(result, expected)
158+
159+
def test_tall_narrow_grid(self):
160+
"""Test with many rows, few columns"""
161+
grid = [
162+
["#"],
163+
["#"],
164+
["#"],
165+
["#"]
166+
]
167+
expected = [["#", "#", "#", "#"]]
168+
result = self.solution.rotateTheBox(grid)
169+
self.assertEqual(result, expected)
170+
171+
def test_wide_short_grid(self):
172+
"""Test with few rows, many columns"""
173+
grid = [["#", ".", "#", ".", "#", "."]]
174+
expected = [
175+
["."],
176+
["."],
177+
["."],
178+
["#"],
179+
["#"],
180+
["#"]
181+
]
182+
result = self.solution.rotateTheBox(grid)
183+
self.assertEqual(result, expected)
184+
185+
def test_stones_stacking(self):
186+
"""Test multiple stones stacking on obstacle"""
187+
grid = [["#", "#", "#", "*"]]
188+
expected = [
189+
["#"],
190+
["#"],
191+
["#"],
192+
["*"]
193+
]
194+
result = self.solution.rotateTheBox(grid)
195+
self.assertEqual(result, expected)
196+
197+
def test_no_gravity_needed(self):
198+
"""Test where no stones need to fall"""
199+
grid = [
200+
["*", "*", "*"],
201+
["#", "#", "#"]
202+
]
203+
expected = [
204+
["#", "*"],
205+
["#", "*"],
206+
["#", "*"]
207+
]
208+
result = self.solution.rotateTheBox(grid)
209+
self.assertEqual(result, expected)
210+
211+
212+
if __name__ == '__main__':
213+
# Run tests with verbose output
214+
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)