Skip to content

Commit b969f83

Browse files
committed
feat(algorithms, greedy): minimimum moves to spread stones
1 parent 57c3839 commit b969f83

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Minimum Moves to Spread Stones Over Grid
2+
3+
Given a 2D grid of integers of size (3 × 3), where each value represents the number of stones in the given cell, return
4+
the minimum number of moves required to place exactly one stone in each grid cell.
5+
6+
## Constraints
7+
8+
- Only one stone can be moved in one move.
9+
- Stone from a cell can only be moved to another cell if they are adjacent (share a side).
10+
- The sum of all stones in the grid must be equal to 9.
11+
- `grid.length`, `grid[i].length` == 3
12+
- 0 <= `grid[i][j]` <= 9
13+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from typing import List
2+
from itertools import permutations
3+
4+
5+
def minimum_moves(grid: List[List[int]]) -> int:
6+
"""
7+
This function finds the minimum number of moves required to place exactly one stone in each grid cell.
8+
9+
Args:
10+
grid(list): 2D grid of integers of size (3 × 3), where each value represents the number of stones in the given
11+
cell
12+
Returns:
13+
int: minimum number of moves required to place exactly one stone in each grid cell
14+
"""
15+
# stores every stone beyond the first one in a cell, this becomes the source
16+
surplus_list = []
17+
# for every cell with 0 stones, this contains the coordinates of that cell. this becomes the target
18+
empty_list = []
19+
20+
minimum_number_of_moves = float("inf")
21+
22+
# iterate through the grid and add the cell that has surplus stones multiple times to the surplus list, for example,
23+
# if cell grid[1][1] has 3 stones, add it twice to the surplus list
24+
for row in range(len(grid)):
25+
for col in range(len(grid[row])):
26+
if grid[row][col] == 0:
27+
empty_list.append([row, col])
28+
elif grid[row][col] > 1:
29+
count = grid[row][col]
30+
for c in range(count - 1):
31+
surplus_list.append([row, col])
32+
33+
# iterate through every possible permutation of the sources, trying every possible assignment to the targets
34+
for perms in permutations(surplus_list):
35+
# calculate the total number of moves for this permutation
36+
total_moves = 0
37+
for i in range(len(perms)):
38+
total_moves += abs(perms[i][0] - empty_list[i][0]) + abs(perms[i][1] - empty_list[i][1])
39+
# return the minimum number of moves
40+
minimum_number_of_moves = min(minimum_number_of_moves, total_moves)
41+
42+
return minimum_number_of_moves
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import unittest
2+
from typing import List
3+
from parameterized import parameterized
4+
from algorithms.greedy.spread_stones import minimum_moves
5+
6+
7+
TEST_CASES = [
8+
([[0, 0, 1], [1, 0, 4], [1, 1, 1]], 6),
9+
([[0, 2, 1], [1, 1, 1], [1, 1, 1]], 1),
10+
([[0, 0, 0], [9, 0, 0], [0, 0, 0]], 15),
11+
([[6, 0, 0], [1, 0, 0], [1, 0, 1]], 11),
12+
([[0, 0, 0], [7, 0, 1], [0, 0, 1]], 10),
13+
]
14+
15+
16+
class MinimumMovesToSpreadStonesTestCase(unittest.TestCase):
17+
@parameterized.expand(TEST_CASES)
18+
def test_something(self, grid: List[List[int]], expected: int):
19+
actual = minimum_moves(grid)
20+
self.assertEqual(expected, actual)
21+
22+
23+
if __name__ == "__main__":
24+
unittest.main()

0 commit comments

Comments
 (0)