-
Notifications
You must be signed in to change notification settings - Fork 0
994. Rotting Oranges #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| ### Step1 | ||
|
|
||
| - 内包表記を多用してみた。どうだろうか。 | ||
| - 意図は明確になるように感じるけど、長くなりがち? | ||
| - minites_plus_oneは流石にわかりにくいかも。 | ||
| - while oranges_rottenのすぐ後でminites_plus_one += 1したいなあと思ってたらこうなってしまった。 | ||
| - あとで気づいたが、xとyが逆でした | ||
|
|
||
| ```python | ||
| class Solution: | ||
| EMPTY = 0 | ||
| FRESH = 1 | ||
| ROTTEN = 2 | ||
|
|
||
| def orangesRotting(self, grid: List[List[int]]) -> int: | ||
| rotting_grid = [row[:] for row in grid] | ||
|
|
||
| def rot_orange_if_fresh(x: int, y: int) -> None: | ||
| if not 0 <= x < len(grid) or not 0 <= y < len(grid[0]): | ||
| return | ||
| if rotting_grid[x][y] != self.FRESH: | ||
| return | ||
| rotting_grid[x][y] = self.ROTTEN | ||
| rotting_oranges.append((x, y)) | ||
|
|
||
| minites_plus_one = 0 | ||
| if all(cell == self.EMPTY for row in grid for cell in row): | ||
| return 0 | ||
| oranges_rotten = [(x, y) for y in range(len(grid[0])) for x in range(len(grid)) if grid[x][y] == self.ROTTEN] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 英語の語順的には |
||
| while oranges_rotten: | ||
| minites_plus_one += 1 | ||
| rotting_oranges = [] | ||
| for x, y in oranges_rotten: | ||
| rot_orange_if_fresh(x + 1, y) | ||
| rot_orange_if_fresh(x - 1, y) | ||
| rot_orange_if_fresh(x, y + 1) | ||
| rot_orange_if_fresh(x, y - 1) | ||
| oranges_rotten = rotting_oranges | ||
| if any(cell == self.FRESH for row in rotting_grid for cell in row): | ||
| return -1 | ||
| return minites_plus_one - 1 | ||
| ``` | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 時間を進めるタイミングが難しいですね。素直に問題文の通りに表現すると すべてのオレンジが腐っているかを確認して、その場合は return という無限ループでしょうか。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ありがとうございます。確かにこれが自然ですね # 略
def orangesRotting(self, grid: List[List[Orange]]) -> int:
minutes = 0
rotten_oranges_so_far = set([(x, y) for y in range(len(grid)) for x in range(len(grid[0])) if grid[y][x] == Orange.ROTTEN])
num_oranges_all = sum(grid[y][x] != Orange.EMPTY for y in range(len(grid)) for x in range(len(grid[0])))
while True:
if len(rotten_oranges_so_far) == num_oranges_all:
return minutes
new_rotten_oranges = self._rot_next_oranges(grid, rotten_oranges_so_far)
minutes += 1
if len(new_rotten_oranges) == 0:
return -1
rotten_oranges_so_far |= new_rotten_orangesこれもアリかなと思ってました # 略
def orangesRotting(self, grid: List[List[Orange]]) -> int:
minutes = 0
rotten_oranges_so_far = set([(x, y) for y in range(len(grid)) for x in range(len(grid[0])) if grid[y][x] == Orange.ROTTEN])
num_oranges_all = sum(grid[y][x] != Orange.EMPTY for y in range(len(grid)) for x in range(len(grid[0])))
while True:
new_rotten_oranges = self._rot_next_oranges(grid, rotten_oranges_so_far)
if len(new_rotten_oranges) == 0:
if len(rotten_oranges_so_far) < num_oranges_all:
return -1
return minutes
rotten_oranges_so_far |= new_rotten_oranges
minutes += 1 |
||
|
|
||
| ## Step2 | ||
|
|
||
| - deepcopyする必要なかった、、、 | ||
| - 以下の悩んだポイント | ||
| - いくらなんでも繰り返し多すぎ?ただ、関数化するとしてもどこまで関数化するかが難しい。 | ||
| - x, yはdataclassとかにした方がいいだろうか、大袈裟? | ||
|
|
||
| ```python | ||
| class Solution: | ||
| EMPTY = 0 | ||
| FRESH = 1 | ||
| ROTTEN = 2 | ||
|
|
||
| def get_initial_rotten_oranges_num_and_coordinates(self, grid: List[List[int]]) -> Tuple[int, Set[Tuple[int, int]]]: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. protected method のため、先頭に |
||
| num_rotten = 0 | ||
| coordinates_rotten = set() | ||
| for y in range(len(grid)): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| for x in range(len(grid[0])): | ||
| if grid[y][x] != self.ROTTEN: | ||
| continue | ||
| num_rotten += 1 | ||
| coordinates_rotten.add((x, y)) | ||
| return num_rotten, coordinates_rotten | ||
|
|
||
| def count_oranges(self, grid: List[List[int]]) -> int: | ||
| num_oranges = 0 | ||
| for y in range(len(grid)): | ||
| for x in range(len(grid[0])): | ||
| if grid[y][x] == self.EMPTY: | ||
| continue | ||
| num_oranges += 1 | ||
| return num_oranges | ||
|
|
||
| def is_fresh(self, x: int, y: int, grid: List[List[int]], coordinates_rotten: Set[Tuple[int, int]]) -> bool: | ||
| if not 0 <= x < len(grid[0]) or not 0 <= y < len(grid): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| return False | ||
| if grid[y][x] == self.EMPTY: | ||
| return False | ||
| if (x, y) in coordinates_rotten: | ||
| return False | ||
| return True | ||
|
|
||
| def orangesRotting(self, grid: List[List[int]]) -> int: | ||
| num_rotten, coordinates_rotten = self.get_initial_rotten_oranges_num_and_coordinates(grid) | ||
| num_all_oranges = self.count_oranges(grid) | ||
| previously_rotten = list(coordinates_rotten) | ||
| result = 0 | ||
| while True: | ||
| rotting = [] | ||
| if num_rotten == num_all_oranges: | ||
| return result | ||
| if not previously_rotten: | ||
| return -1 | ||
| for x, y in previously_rotten: | ||
| if self.is_fresh(x + 1, y, grid, coordinates_rotten): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. deltas = [(0, 1), (0, -1), (1, 0), (-1, 0)]
...
for delta in deltas:
if (self.is_fresh(x + delta[0], y + delta[1], grid, coordinates_rotten)):といった感じにすると、コードの重複が減ると思いました。 |
||
| num_rotten += 1 | ||
| coordinates_rotten.add((x + 1, y)) | ||
| rotting.append((x + 1, y)) | ||
| if self.is_fresh(x - 1, y, grid, coordinates_rotten): | ||
| num_rotten += 1 | ||
| coordinates_rotten.add((x - 1, y)) | ||
| rotting.append((x - 1, y)) | ||
| if self.is_fresh(x , y + 1, grid, coordinates_rotten): | ||
| num_rotten += 1 | ||
| coordinates_rotten.add((x , y + 1)) | ||
| rotting.append((x , y + 1)) | ||
| if self.is_fresh(x, y - 1, grid, coordinates_rotten): | ||
| num_rotten += 1 | ||
| coordinates_rotten.add((x , y - 1)) | ||
| rotting.append((x , y - 1)) | ||
| previously_rotten = rotting | ||
| result += 1 | ||
|
|
||
| ``` | ||
|
|
||
| https://discord.com/channels/1084280443945353267/1200089668901937312/1201562858295656599 | ||
|
|
||
| - 上の自分のコードは、関係性がある(lenとか差集合とかの関連がある)変数が多い割にそれぞれ別で処理しているので、追うのが大変になってるかも。変数管理が大変? | ||
| - set()のメソッドを読む | ||
| - https://docs.python.org/3/library/stdtypes.html#set | ||
| - remove(elem)とかdiscard(elem)とか知らなかった(昔見たかもしれないが、忘れていた) | ||
| - 前者はelemがない場合ValueError, 後者は単に無視 | ||
| - IntEnumが便利そう | ||
| - 0, 1, 2以外が入っても、型チェックをonにしたら弾いてくれる | ||
| - num_rottenは、get_initial_oranges_of_rottenで計算せずに、単にlen(rotten_coordinates)でよかったかも | ||
|
|
||
| ```python | ||
| from enum import IntEnum | ||
|
|
||
| class Orange(IntEnum): | ||
| EMPTY = 0 | ||
| FRESH = 1 | ||
| ROTTEN = 2 | ||
|
|
||
| class Solution: | ||
| def is_fresh(self, grid: List[List[Orange]], x: int, y: int, rotten_so_far: Set[Tuple[int, int]]) -> bool: | ||
| if not 0 <= x < len(grid[0]) or not 0 <= y < len(grid): | ||
| return False | ||
| if grid[y][x] == Orange.EMPTY: | ||
| return False | ||
| if (x, y) in rotten_so_far: | ||
| return False | ||
| return True | ||
|
|
||
| def count_oranges(self, grid: List[List[Orange]]) -> int: | ||
| num_oranges = 0 | ||
| for y in range(len(grid)): | ||
| for x in range(len(grid[0])): | ||
| if grid[y][x] == Orange.EMPTY: | ||
| continue | ||
| num_oranges += 1 | ||
| return num_oranges | ||
|
|
||
| def get_initial_oranges_of_rotten(self, grid: List[List[Orange]]) -> Tuple[int, Set[Tuple[int, int]]]: | ||
| rotten_coordinates = set() | ||
| num_rotten = 0 | ||
| for y in range(len(grid)): | ||
| for x in range(len(grid[0])): | ||
| if grid[y][x] != Orange.ROTTEN: | ||
| continue | ||
| rotten_coordinates.add((x, y)) | ||
| num_rotten += 1 | ||
| return num_rotten, rotten_coordinates | ||
|
|
||
| def orangesRotting(self, grid: List[List[Orange]]) -> int: | ||
| num_rotten, rotten_coordinates = self.get_initial_oranges_of_rotten(grid) | ||
| previous_rotten = rotten_coordinates.copy() | ||
| num_oranges = self.count_oranges(grid) | ||
| minutes = 0 | ||
| while num_rotten < num_oranges: | ||
| rotting = set() | ||
| for x, y in previous_rotten: | ||
| if self.is_fresh(grid, x + 1, y, rotten_coordinates): | ||
| rotting.add((x + 1, y)) | ||
| if self.is_fresh(grid, x - 1, y, rotten_coordinates): | ||
| rotting.add((x - 1, y)) | ||
| if self.is_fresh(grid, x, y + 1, rotten_coordinates): | ||
| rotting.add((x, y + 1)) | ||
| if self.is_fresh(grid, x, y - 1, rotten_coordinates): | ||
| rotting.add((x, y - 1)) | ||
| if not rotting: | ||
| return -1 # impossible | ||
| rotten_coordinates |= rotting | ||
| num_rotten += len(rotting) | ||
| previous_rotten = rotting | ||
| minutes += 1 | ||
| return minutes | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
個人的にはx,yで命名すると結構混乱する気がするんですよね。row, colとかのほうが個人的にはわかりやすいです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます。rowとcolも自分は結構混乱するんですよね、、、(が、これは自分が覚えた方が良い気がしてきました)