From ef6cff50ccf578af24d55565b631fd99956db3cb Mon Sep 17 00:00:00 2001 From: Rhitik Date: Sat, 14 Oct 2023 21:04:18 +0530 Subject: [PATCH 01/11] Added Solution for 1912. Movie Rental System in python. --- .../1912.Design Movie Rental System/README.md | 26 ++++++++++++++++++ .../README_EN.md | 27 ++++++++++++++++++- .../Solution.py | 26 ++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 solution/1900-1999/1912.Design Movie Rental System/Solution.py diff --git a/solution/1900-1999/1912.Design Movie Rental System/README.md b/solution/1900-1999/1912.Design Movie Rental System/README.md index 0a8c0c09ec8e8..6238f8e94c651 100644 --- a/solution/1900-1999/1912.Design Movie Rental System/README.md +++ b/solution/1900-1999/1912.Design Movie Rental System/README.md @@ -76,6 +76,32 @@ movieRentingSystem.search(2); // 返回 [0, 1] 。商店 0 和 1 有未借出 ```python +from sortedcontainers import SortedList + +class MovieRentingSystem: + def __init__(self, n: int, entries: List[List[int]]): + self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} + self.shopAndMovieToPrice = {} # {(shop, movie): price} + self.rented = SortedList() # (price, shop, movie) + for shop, movie, price in entries: + self.unrented[movie].add((price, shop)) + self.shopAndMovieToPrice[(shop, movie)] = price + + def search(self, movie: int) -> List[int]: + return [shop for _, shop in self.unrented[movie][:5]] + + def rent(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].remove((price, shop)) + self.rented.add((price, shop, movie)) + + def drop(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].add((price, shop)) + self.rented.remove((price, shop, movie)) + + def report(self) -> List[List[int]]: + return [[shop, movie] for _, shop, movie in self.rented[:5]] ``` diff --git a/solution/1900-1999/1912.Design Movie Rental System/README_EN.md b/solution/1900-1999/1912.Design Movie Rental System/README_EN.md index b5f20dc46734f..18a5f67c40a28 100644 --- a/solution/1900-1999/1912.Design Movie Rental System/README_EN.md +++ b/solution/1900-1999/1912.Design Movie Rental System/README_EN.md @@ -68,7 +68,32 @@ movieRentingSystem.search(2); // return [0, 1]. Movies of ID 2 are unrented at ### **Python3** ```python - +from sortedcontainers import SortedList + +class MovieRentingSystem: + def __init__(self, n: int, entries: List[List[int]]): + self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} + self.shopAndMovieToPrice = {} # {(shop, movie): price} + self.rented = SortedList() # (price, shop, movie) + for shop, movie, price in entries: + self.unrented[movie].add((price, shop)) + self.shopAndMovieToPrice[(shop, movie)] = price + + def search(self, movie: int) -> List[int]: + return [shop for _, shop in self.unrented[movie][:5]] + + def rent(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].remove((price, shop)) + self.rented.add((price, shop, movie)) + + def drop(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].add((price, shop)) + self.rented.remove((price, shop, movie)) + + def report(self) -> List[List[int]]: + return [[shop, movie] for _, shop, movie in self.rented[:5]] ``` ### **Java** diff --git a/solution/1900-1999/1912.Design Movie Rental System/Solution.py b/solution/1900-1999/1912.Design Movie Rental System/Solution.py new file mode 100644 index 0000000000000..3f0d1211a48b5 --- /dev/null +++ b/solution/1900-1999/1912.Design Movie Rental System/Solution.py @@ -0,0 +1,26 @@ +from sortedcontainers import SortedList + +class MovieRentingSystem: + def __init__(self, n: int, entries: List[List[int]]): + self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} + self.shopAndMovieToPrice = {} # {(shop, movie): price} + self.rented = SortedList() # (price, shop, movie) + for shop, movie, price in entries: + self.unrented[movie].add((price, shop)) + self.shopAndMovieToPrice[(shop, movie)] = price + + def search(self, movie: int) -> List[int]: + return [shop for _, shop in self.unrented[movie][:5]] + + def rent(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].remove((price, shop)) + self.rented.add((price, shop, movie)) + + def drop(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].add((price, shop)) + self.rented.remove((price, shop, movie)) + + def report(self) -> List[List[int]]: + return [[shop, movie] for _, shop, movie in self.rented[:5]] From ca705c1a5219ad38c6314b32291499de6bd797be Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Sun, 15 Oct 2023 09:18:27 +0800 Subject: [PATCH 02/11] Update README.md --- .../1912.Design Movie Rental System/README.md | 56 +++++++++++-------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/solution/1900-1999/1912.Design Movie Rental System/README.md b/solution/1900-1999/1912.Design Movie Rental System/README.md index 6238f8e94c651..569ffe773e617 100644 --- a/solution/1900-1999/1912.Design Movie Rental System/README.md +++ b/solution/1900-1999/1912.Design Movie Rental System/README.md @@ -78,31 +78,39 @@ movieRentingSystem.search(2); // 返回 [0, 1] 。商店 0 和 1 有未借出 ```python from sortedcontainers import SortedList -class MovieRentingSystem: - def __init__(self, n: int, entries: List[List[int]]): - self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} - self.shopAndMovieToPrice = {} # {(shop, movie): price} - self.rented = SortedList() # (price, shop, movie) - for shop, movie, price in entries: - self.unrented[movie].add((price, shop)) - self.shopAndMovieToPrice[(shop, movie)] = price - - def search(self, movie: int) -> List[int]: - return [shop for _, shop in self.unrented[movie][:5]] - - def rent(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].remove((price, shop)) - self.rented.add((price, shop, movie)) - - def drop(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].add((price, shop)) - self.rented.remove((price, shop, movie)) - - def report(self) -> List[List[int]]: - return [[shop, movie] for _, shop, movie in self.rented[:5]] +class MovieRentingSystem: + def __init__(self, n: int, entries: List[List[int]]): + self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} + self.shopAndMovieToPrice = {} # {(shop, movie): price} + self.rented = SortedList() # (price, shop, movie) + for shop, movie, price in entries: + self.unrented[movie].add((price, shop)) + self.shopAndMovieToPrice[(shop, movie)] = price + + def search(self, movie: int) -> List[int]: + return [shop for _, shop in self.unrented[movie][:5]] + + def rent(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].remove((price, shop)) + self.rented.add((price, shop, movie)) + + def drop(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].add((price, shop)) + self.rented.remove((price, shop, movie)) + + def report(self) -> List[List[int]]: + return [[shop, movie] for _, shop, movie in self.rented[:5]] + + +# Your MovieRentingSystem object will be instantiated and called as such: +# obj = MovieRentingSystem(n, entries) +# param_1 = obj.search(movie) +# obj.rent(shop,movie) +# obj.drop(shop,movie) +# param_4 = obj.report() ``` ### **Java** From 727bd2c6d20bb8c8fd7916b0414064eba09aa21f Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Sun, 15 Oct 2023 09:18:46 +0800 Subject: [PATCH 03/11] Update README_EN.md --- .../README_EN.md | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/solution/1900-1999/1912.Design Movie Rental System/README_EN.md b/solution/1900-1999/1912.Design Movie Rental System/README_EN.md index 18a5f67c40a28..8276a456cdb36 100644 --- a/solution/1900-1999/1912.Design Movie Rental System/README_EN.md +++ b/solution/1900-1999/1912.Design Movie Rental System/README_EN.md @@ -70,30 +70,39 @@ movieRentingSystem.search(2); // return [0, 1]. Movies of ID 2 are unrented at ```python from sortedcontainers import SortedList + class MovieRentingSystem: - def __init__(self, n: int, entries: List[List[int]]): - self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} - self.shopAndMovieToPrice = {} # {(shop, movie): price} - self.rented = SortedList() # (price, shop, movie) - for shop, movie, price in entries: - self.unrented[movie].add((price, shop)) - self.shopAndMovieToPrice[(shop, movie)] = price - - def search(self, movie: int) -> List[int]: - return [shop for _, shop in self.unrented[movie][:5]] - - def rent(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].remove((price, shop)) - self.rented.add((price, shop, movie)) - - def drop(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].add((price, shop)) - self.rented.remove((price, shop, movie)) - - def report(self) -> List[List[int]]: - return [[shop, movie] for _, shop, movie in self.rented[:5]] + def __init__(self, n: int, entries: List[List[int]]): + self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} + self.shopAndMovieToPrice = {} # {(shop, movie): price} + self.rented = SortedList() # (price, shop, movie) + for shop, movie, price in entries: + self.unrented[movie].add((price, shop)) + self.shopAndMovieToPrice[(shop, movie)] = price + + def search(self, movie: int) -> List[int]: + return [shop for _, shop in self.unrented[movie][:5]] + + def rent(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].remove((price, shop)) + self.rented.add((price, shop, movie)) + + def drop(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].add((price, shop)) + self.rented.remove((price, shop, movie)) + + def report(self) -> List[List[int]]: + return [[shop, movie] for _, shop, movie in self.rented[:5]] + + +# Your MovieRentingSystem object will be instantiated and called as such: +# obj = MovieRentingSystem(n, entries) +# param_1 = obj.search(movie) +# obj.rent(shop,movie) +# obj.drop(shop,movie) +# param_4 = obj.report() ``` ### **Java** From d1241abfeaff70a0cc28922eb95bdf96631b241e Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Sun, 15 Oct 2023 09:27:54 +0800 Subject: [PATCH 04/11] Update Solution.py --- .../Solution.py | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/solution/1900-1999/1912.Design Movie Rental System/Solution.py b/solution/1900-1999/1912.Design Movie Rental System/Solution.py index 3f0d1211a48b5..3f309835db942 100644 --- a/solution/1900-1999/1912.Design Movie Rental System/Solution.py +++ b/solution/1900-1999/1912.Design Movie Rental System/Solution.py @@ -1,26 +1,35 @@ from sortedcontainers import SortedList + class MovieRentingSystem: - def __init__(self, n: int, entries: List[List[int]]): - self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} - self.shopAndMovieToPrice = {} # {(shop, movie): price} - self.rented = SortedList() # (price, shop, movie) - for shop, movie, price in entries: - self.unrented[movie].add((price, shop)) - self.shopAndMovieToPrice[(shop, movie)] = price - - def search(self, movie: int) -> List[int]: - return [shop for _, shop in self.unrented[movie][:5]] - - def rent(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].remove((price, shop)) - self.rented.add((price, shop, movie)) - - def drop(self, shop: int, movie: int) -> None: - price = self.shopAndMovieToPrice[(shop, movie)] - self.unrented[movie].add((price, shop)) - self.rented.remove((price, shop, movie)) - - def report(self) -> List[List[int]]: - return [[shop, movie] for _, shop, movie in self.rented[:5]] + def __init__(self, n: int, entries: List[List[int]]): + self.unrented = collections.defaultdict(SortedList) # {movie: (price, shop)} + self.shopAndMovieToPrice = {} # {(shop, movie): price} + self.rented = SortedList() # (price, shop, movie) + for shop, movie, price in entries: + self.unrented[movie].add((price, shop)) + self.shopAndMovieToPrice[(shop, movie)] = price + + def search(self, movie: int) -> List[int]: + return [shop for _, shop in self.unrented[movie][:5]] + + def rent(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].remove((price, shop)) + self.rented.add((price, shop, movie)) + + def drop(self, shop: int, movie: int) -> None: + price = self.shopAndMovieToPrice[(shop, movie)] + self.unrented[movie].add((price, shop)) + self.rented.remove((price, shop, movie)) + + def report(self) -> List[List[int]]: + return [[shop, movie] for _, shop, movie in self.rented[:5]] + + +# Your MovieRentingSystem object will be instantiated and called as such: +# obj = MovieRentingSystem(n, entries) +# param_1 = obj.search(movie) +# obj.rent(shop,movie) +# obj.drop(shop,movie) +# param_4 = obj.report() From a02c4095bda9b8fd96b86b42777a6606dc80fd5c Mon Sep 17 00:00:00 2001 From: Rhitik Date: Mon, 16 Oct 2023 01:07:12 +0530 Subject: [PATCH 05/11] Solution for 1900. Earliest and Latest Rounds Where Players Compete. --- .../README.md | 28 +++++++++++++++++++ .../README_EN.md | 28 +++++++++++++++++++ .../Solution.py | 28 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/Solution.py diff --git a/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/README.md b/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/README.md index 254647517b86f..50143e1ed8128 100644 --- a/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/README.md +++ b/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/README.md @@ -74,6 +74,34 @@ ```python +class Solution: + def earliestAndLatest( + self, n: int, firstPlayer: int, secondPlayer: int + ) -> List[int]: + # dp[i][j][k] := (earliest, latest) pair w/ firstPlayer is i-th player from + # Front, secondPlayer is j-th player from end, and there're k people + @functools.lru_cache(None) + def dp(l: int, r: int, k: int) -> List[int]: + if l == r: + return [1, 1] + if l > r: + return dp(r, l, k) + + a = math.inf + b = -math.inf + + # Enumerate all possible positions + for i in range(1, l + 1): + for j in range(l - i + 1, r - i + 1): + if not l + r - k // 2 <= i + j <= (k + 1) // 2: + continue + x, y = dp(i, j, (k + 1) // 2) + a = min(a, x + 1) + b = max(b, y + 1) + + return [a, b] + + return dp(firstPlayer, n - secondPlayer + 1, n) ``` diff --git a/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/README_EN.md b/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/README_EN.md index 44caf76986813..35a38bf73fbfc 100644 --- a/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/README_EN.md +++ b/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/README_EN.md @@ -68,6 +68,34 @@ There is no way to make them compete in any other round. ### **Python3** ```python +class Solution: + def earliestAndLatest( + self, n: int, firstPlayer: int, secondPlayer: int + ) -> List[int]: + # dp[i][j][k] := (earliest, latest) pair w/ firstPlayer is i-th player from + # Front, secondPlayer is j-th player from end, and there're k people + @functools.lru_cache(None) + def dp(l: int, r: int, k: int) -> List[int]: + if l == r: + return [1, 1] + if l > r: + return dp(r, l, k) + + a = math.inf + b = -math.inf + + # Enumerate all possible positions + for i in range(1, l + 1): + for j in range(l - i + 1, r - i + 1): + if not l + r - k // 2 <= i + j <= (k + 1) // 2: + continue + x, y = dp(i, j, (k + 1) // 2) + a = min(a, x + 1) + b = max(b, y + 1) + + return [a, b] + + return dp(firstPlayer, n - secondPlayer + 1, n) ``` diff --git a/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/Solution.py b/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/Solution.py new file mode 100644 index 0000000000000..f16f724b7a0ab --- /dev/null +++ b/solution/1900-1999/1900.The Earliest and Latest Rounds Where Players Compete/Solution.py @@ -0,0 +1,28 @@ +class Solution: + def earliestAndLatest( + self, n: int, firstPlayer: int, secondPlayer: int + ) -> List[int]: + # dp[i][j][k] := (earliest, latest) pair w/ firstPlayer is i-th player from + # Front, secondPlayer is j-th player from end, and there're k people + @functools.lru_cache(None) + def dp(l: int, r: int, k: int) -> List[int]: + if l == r: + return [1, 1] + if l > r: + return dp(r, l, k) + + a = math.inf + b = -math.inf + + # Enumerate all possible positions + for i in range(1, l + 1): + for j in range(l - i + 1, r - i + 1): + if not l + r - k // 2 <= i + j <= (k + 1) // 2: + continue + x, y = dp(i, j, (k + 1) // 2) + a = min(a, x + 1) + b = max(b, y + 1) + + return [a, b] + + return dp(firstPlayer, n - secondPlayer + 1, n) From dd85b2ca656cb36757ac42ecb7f20d24f22cde6b Mon Sep 17 00:00:00 2001 From: Rhitik Date: Mon, 16 Oct 2023 17:15:03 +0530 Subject: [PATCH 06/11] Added Solution for 1307. Verbal Arithmetic Puzzel and Updated README.md and README_EN.md --- .../1307.Verbal Arithmetic Puzzle/README.md | 39 +++++++++++++++++++ .../README_EN.md | 39 +++++++++++++++++++ .../1307.Verbal Arithmetic Puzzle/Solution.py | 39 +++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py diff --git a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md index 4c4659ecb9f0d..8a38194b377d5 100644 --- a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md +++ b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md @@ -69,6 +69,45 @@ ```python +class Solution: + def isSolvable(self, words: List[str], result: str) -> bool: + words.append(result) + rows = len(words) + cols = max(map(len, words)) + letterToDigit = {} + usedDigit = [False] * 10 + + def dfs(row: int, col: int, summ: int) -> bool: + if col == cols: + return summ == 0 + if row == rows: + return summ % 10 == 0 and dfs(0, col + 1, summ // 10) + + word = words[row] + if col >= len(word): + return dfs(row + 1, col, summ) + + letter = word[~col] + sign = -1 if row == rows - 1 else 1 + + if letter in letterToDigit and ( + letterToDigit[letter] > 0 or col < len(word) - 1 + ): + return dfs(row + 1, col, summ + sign * letterToDigit[letter]) + + for digit, used in enumerate(usedDigit): + if not used and (digit > 0 or col < len(word) - 1): + letterToDigit[letter] = digit + usedDigit[digit] = True + if dfs(row + 1, col, summ + sign * digit): + return True + usedDigit[digit] = False + if letter in letterToDigit: + del letterToDigit[letter] + + return False + + return dfs(0, 0, 0) ``` diff --git a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md index 6fe660b2b7903..9d9fa88ceba28 100644 --- a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md +++ b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md @@ -60,6 +60,45 @@ Note that two different characters cannot map to the same digit. ### **Python3** ```python +class Solution: + def isSolvable(self, words: List[str], result: str) -> bool: + words.append(result) + rows = len(words) + cols = max(map(len, words)) + letterToDigit = {} + usedDigit = [False] * 10 + + def dfs(row: int, col: int, summ: int) -> bool: + if col == cols: + return summ == 0 + if row == rows: + return summ % 10 == 0 and dfs(0, col + 1, summ // 10) + + word = words[row] + if col >= len(word): + return dfs(row + 1, col, summ) + + letter = word[~col] + sign = -1 if row == rows - 1 else 1 + + if letter in letterToDigit and ( + letterToDigit[letter] > 0 or col < len(word) - 1 + ): + return dfs(row + 1, col, summ + sign * letterToDigit[letter]) + + for digit, used in enumerate(usedDigit): + if not used and (digit > 0 or col < len(word) - 1): + letterToDigit[letter] = digit + usedDigit[digit] = True + if dfs(row + 1, col, summ + sign * digit): + return True + usedDigit[digit] = False + if letter in letterToDigit: + del letterToDigit[letter] + + return False + + return dfs(0, 0, 0) ``` diff --git a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py new file mode 100644 index 0000000000000..175fed29a1015 --- /dev/null +++ b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py @@ -0,0 +1,39 @@ +class Solution: + def isSolvable(self, words: List[str], result: str) -> bool: + words.append(result) + rows = len(words) + cols = max(map(len, words)) + letterToDigit = {} + usedDigit = [False] * 10 + + def dfs(row: int, col: int, summ: int) -> bool: + if col == cols: + return summ == 0 + if row == rows: + return summ % 10 == 0 and dfs(0, col + 1, summ // 10) + + word = words[row] + if col >= len(word): + return dfs(row + 1, col, summ) + + letter = word[~col] + sign = -1 if row == rows - 1 else 1 + + if letter in letterToDigit and ( + letterToDigit[letter] > 0 or col < len(word) - 1 + ): + return dfs(row + 1, col, summ + sign * letterToDigit[letter]) + + for digit, used in enumerate(usedDigit): + if not used and (digit > 0 or col < len(word) - 1): + letterToDigit[letter] = digit + usedDigit[digit] = True + if dfs(row + 1, col, summ + sign * digit): + return True + usedDigit[digit] = False + if letter in letterToDigit: + del letterToDigit[letter] + + return False + + return dfs(0, 0, 0) From cce5b39cc76ea6ae47eabdb708c67cc1c71dd7c2 Mon Sep 17 00:00:00 2001 From: Rhitik Date: Mon, 16 Oct 2023 17:18:16 +0530 Subject: [PATCH 07/11] Added solution for 1354. --- .../README.md | 23 +++++++++++++++++++ .../README_EN.md | 23 +++++++++++++++++++ .../Solution.py | 23 +++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 solution/1300-1399/1354.Construct Target Array With Multiple Sums/Solution.py diff --git a/solution/1300-1399/1354.Construct Target Array With Multiple Sums/README.md b/solution/1300-1399/1354.Construct Target Array With Multiple Sums/README.md index 41867015b1e1d..2f70357cedf60 100644 --- a/solution/1300-1399/1354.Construct Target Array With Multiple Sums/README.md +++ b/solution/1300-1399/1354.Construct Target Array With Multiple Sums/README.md @@ -63,6 +63,29 @@ ```python +class Solution: + def isPossible(self, target: List[int]) -> bool: + if len(target) == 1: + return target[0] == 1 + + summ = sum(target) + maxHeap = [-num for num in target] + heapq.heapify(maxHeap) + + while -maxHeap[0] > 1: + maxi = -heapq.heappop(maxHeap) + restSum = summ - maxi + # Only occurs if n == 2. + if restSum == 1: + return True + updated = maxi % restSum + # Updated == 0 (invalid) or didn't change. + if updated == 0 or updated == maxi: + return False + heapq.heappush(maxHeap, -updated) + summ = summ - maxi + updated + + return True ``` diff --git a/solution/1300-1399/1354.Construct Target Array With Multiple Sums/README_EN.md b/solution/1300-1399/1354.Construct Target Array With Multiple Sums/README_EN.md index 64cb1603eaf11..7839c8a3ff817 100644 --- a/solution/1300-1399/1354.Construct Target Array With Multiple Sums/README_EN.md +++ b/solution/1300-1399/1354.Construct Target Array With Multiple Sums/README_EN.md @@ -58,6 +58,29 @@ ### **Python3** ```python +class Solution: + def isPossible(self, target: List[int]) -> bool: + if len(target) == 1: + return target[0] == 1 + + summ = sum(target) + maxHeap = [-num for num in target] + heapq.heapify(maxHeap) + + while -maxHeap[0] > 1: + maxi = -heapq.heappop(maxHeap) + restSum = summ - maxi + # Only occurs if n == 2. + if restSum == 1: + return True + updated = maxi % restSum + # Updated == 0 (invalid) or didn't change. + if updated == 0 or updated == maxi: + return False + heapq.heappush(maxHeap, -updated) + summ = summ - maxi + updated + + return True ``` diff --git a/solution/1300-1399/1354.Construct Target Array With Multiple Sums/Solution.py b/solution/1300-1399/1354.Construct Target Array With Multiple Sums/Solution.py new file mode 100644 index 0000000000000..ec3ecc99ba728 --- /dev/null +++ b/solution/1300-1399/1354.Construct Target Array With Multiple Sums/Solution.py @@ -0,0 +1,23 @@ +class Solution: + def isPossible(self, target: List[int]) -> bool: + if len(target) == 1: + return target[0] == 1 + + summ = sum(target) + maxHeap = [-num for num in target] + heapq.heapify(maxHeap) + + while -maxHeap[0] > 1: + maxi = -heapq.heappop(maxHeap) + restSum = summ - maxi + # Only occurs if n == 2. + if restSum == 1: + return True + updated = maxi % restSum + # Updated == 0 (invalid) or didn't change. + if updated == 0 or updated == maxi: + return False + heapq.heappush(maxHeap, -updated) + summ = summ - maxi + updated + + return True From b1d5882ba0ddb3d9c6e86286e0b9ab20e4cfe15f Mon Sep 17 00:00:00 2001 From: Rhitik Date: Mon, 16 Oct 2023 18:49:26 +0530 Subject: [PATCH 08/11] Updated solution for 1307 to pass all the test cases. --- .../1307.Verbal Arithmetic Puzzle/Solution.py | 77 +++++++++++-------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py index 175fed29a1015..53b0787aff3a6 100644 --- a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py +++ b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py @@ -1,39 +1,56 @@ class Solution: def isSolvable(self, words: List[str], result: str) -> bool: - words.append(result) - rows = len(words) - cols = max(map(len, words)) - letterToDigit = {} - usedDigit = [False] * 10 - - def dfs(row: int, col: int, summ: int) -> bool: - if col == cols: - return summ == 0 - if row == rows: - return summ % 10 == 0 and dfs(0, col + 1, summ // 10) + if max(map(len, words)) > len( + result + ): # If any of the words are bigger than the result, it will be impossible to solve + return False + # Add the result to the list, this way we will only subtract values when it comes to the result word. + # Thus at every index, if the total is zero, then for that letter index the formulat is correct + words = [word[::-1] for word in words] + [result[::-1]] + values = {} # Mapping from letter to values + nums = [0] * 10 - word = words[row] - if col >= len(word): - return dfs(row + 1, col, summ) + # i: word index, j: ltr index, total: total current Sum + def dfs(i, j, total): + if j == len( + result + ): # Reached end of the indecies for ltrs in all words (END) + return ( + total % 10 == 0 + ) # Checking to see if the total for the current character is correct or not + if i == len(words): # Checked ltr at index j for all the words + return total % 10 == 0 and dfs(0, j + 1, total // 10) - letter = word[~col] - sign = -1 if row == rows - 1 else 1 + if j >= len(words[i]): + return dfs(i + 1, j, total) - if letter in letterToDigit and ( - letterToDigit[letter] > 0 or col < len(word) - 1 - ): - return dfs(row + 1, col, summ + sign * letterToDigit[letter]) + if words[i][j] in values: + if ( + values[words[i][j]] == 0 + and j == len(words[i]) - 1 + and len(words[i]) > 1 + ): + return False + if i == len(words) - 1: + return dfs(i + 1, j, total - values[words[i][j]]) + else: + return dfs(i + 1, j, total + values[words[i][j]]) + else: + for val, isUsed in enumerate(nums): + if not isUsed and (val != 0 or j == 0 or j < len(words[i]) - 1): + values[words[i][j]] = val + nums[val] = True - for digit, used in enumerate(usedDigit): - if not used and (digit > 0 or col < len(word) - 1): - letterToDigit[letter] = digit - usedDigit[digit] = True - if dfs(row + 1, col, summ + sign * digit): - return True - usedDigit[digit] = False - if letter in letterToDigit: - del letterToDigit[letter] + if i == len(words) - 1 and dfs( + i + 1, j, total - values[words[i][j]] + ): + return True + elif i < len(words) - 1 and dfs( + i + 1, j, total + values[words[i][j]] + ): + return True - return False + values.pop(words[i][j]) + nums[val] = False return dfs(0, 0, 0) From ea5191338edce227eecebe458d648cd3bde08d31 Mon Sep 17 00:00:00 2001 From: Rhitik Date: Mon, 16 Oct 2023 18:53:50 +0530 Subject: [PATCH 09/11] Updated README for 1307. --- .../1307.Verbal Arithmetic Puzzle/README.md | 85 ++++++++++-------- .../README_EN.md | 86 +++++++++++-------- 2 files changed, 102 insertions(+), 69 deletions(-) diff --git a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md index 8a38194b377d5..716480fb96f05 100644 --- a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md +++ b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md @@ -71,41 +71,58 @@ ```python class Solution: def isSolvable(self, words: List[str], result: str) -> bool: - words.append(result) - rows = len(words) - cols = max(map(len, words)) - letterToDigit = {} - usedDigit = [False] * 10 - - def dfs(row: int, col: int, summ: int) -> bool: - if col == cols: - return summ == 0 - if row == rows: - return summ % 10 == 0 and dfs(0, col + 1, summ // 10) - - word = words[row] - if col >= len(word): - return dfs(row + 1, col, summ) - - letter = word[~col] - sign = -1 if row == rows - 1 else 1 - - if letter in letterToDigit and ( - letterToDigit[letter] > 0 or col < len(word) - 1 - ): - return dfs(row + 1, col, summ + sign * letterToDigit[letter]) - - for digit, used in enumerate(usedDigit): - if not used and (digit > 0 or col < len(word) - 1): - letterToDigit[letter] = digit - usedDigit[digit] = True - if dfs(row + 1, col, summ + sign * digit): - return True - usedDigit[digit] = False - if letter in letterToDigit: - del letterToDigit[letter] - + if max(map(len, words)) > len( + result + ): # If any of the words are bigger than the result, it will be impossible to solve return False + # Add the result to the list, this way we will only subtract values when it comes to the result word. + # Thus at every index, if the total is zero, then for that letter index the formulat is correct + words = [word[::-1] for word in words] + [result[::-1]] + values = {} # Mapping from letter to values + nums = [0] * 10 + + # i: word index, j: ltr index, total: total current Sum + def dfs(i, j, total): + if j == len( + result + ): # Reached end of the indecies for ltrs in all words (END) + return ( + total % 10 == 0 + ) # Checking to see if the total for the current character is correct or not + if i == len(words): # Checked ltr at index j for all the words + return total % 10 == 0 and dfs(0, j + 1, total // 10) + + if j >= len(words[i]): + return dfs(i + 1, j, total) + + if words[i][j] in values: + if ( + values[words[i][j]] == 0 + and j == len(words[i]) - 1 + and len(words[i]) > 1 + ): + return False + if i == len(words) - 1: + return dfs(i + 1, j, total - values[words[i][j]]) + else: + return dfs(i + 1, j, total + values[words[i][j]]) + else: + for val, isUsed in enumerate(nums): + if not isUsed and (val != 0 or j == 0 or j < len(words[i]) - 1): + values[words[i][j]] = val + nums[val] = True + + if i == len(words) - 1 and dfs( + i + 1, j, total - values[words[i][j]] + ): + return True + elif i < len(words) - 1 and dfs( + i + 1, j, total + values[words[i][j]] + ): + return True + + values.pop(words[i][j]) + nums[val] = False return dfs(0, 0, 0) diff --git a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md index 9d9fa88ceba28..7bfd90e001cb5 100644 --- a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md +++ b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md @@ -62,44 +62,60 @@ Note that two different characters cannot map to the same digit. ```python class Solution: def isSolvable(self, words: List[str], result: str) -> bool: - words.append(result) - rows = len(words) - cols = max(map(len, words)) - letterToDigit = {} - usedDigit = [False] * 10 - - def dfs(row: int, col: int, summ: int) -> bool: - if col == cols: - return summ == 0 - if row == rows: - return summ % 10 == 0 and dfs(0, col + 1, summ // 10) - - word = words[row] - if col >= len(word): - return dfs(row + 1, col, summ) - - letter = word[~col] - sign = -1 if row == rows - 1 else 1 - - if letter in letterToDigit and ( - letterToDigit[letter] > 0 or col < len(word) - 1 - ): - return dfs(row + 1, col, summ + sign * letterToDigit[letter]) - - for digit, used in enumerate(usedDigit): - if not used and (digit > 0 or col < len(word) - 1): - letterToDigit[letter] = digit - usedDigit[digit] = True - if dfs(row + 1, col, summ + sign * digit): - return True - usedDigit[digit] = False - if letter in letterToDigit: - del letterToDigit[letter] - + if max(map(len, words)) > len( + result + ): # If any of the words are bigger than the result, it will be impossible to solve return False + # Add the result to the list, this way we will only subtract values when it comes to the result word. + # Thus at every index, if the total is zero, then for that letter index the formulat is correct + words = [word[::-1] for word in words] + [result[::-1]] + values = {} # Mapping from letter to values + nums = [0] * 10 + + # i: word index, j: ltr index, total: total current Sum + def dfs(i, j, total): + if j == len( + result + ): # Reached end of the indecies for ltrs in all words (END) + return ( + total % 10 == 0 + ) # Checking to see if the total for the current character is correct or not + if i == len(words): # Checked ltr at index j for all the words + return total % 10 == 0 and dfs(0, j + 1, total // 10) + + if j >= len(words[i]): + return dfs(i + 1, j, total) + + if words[i][j] in values: + if ( + values[words[i][j]] == 0 + and j == len(words[i]) - 1 + and len(words[i]) > 1 + ): + return False + if i == len(words) - 1: + return dfs(i + 1, j, total - values[words[i][j]]) + else: + return dfs(i + 1, j, total + values[words[i][j]]) + else: + for val, isUsed in enumerate(nums): + if not isUsed and (val != 0 or j == 0 or j < len(words[i]) - 1): + values[words[i][j]] = val + nums[val] = True + + if i == len(words) - 1 and dfs( + i + 1, j, total - values[words[i][j]] + ): + return True + elif i < len(words) - 1 and dfs( + i + 1, j, total + values[words[i][j]] + ): + return True + + values.pop(words[i][j]) + nums[val] = False return dfs(0, 0, 0) - ``` ### **Java** From 68821c3a1f9782c9d6e4a14d03e78e65511a8f57 Mon Sep 17 00:00:00 2001 From: Rhitik Date: Wed, 18 Oct 2023 20:36:41 +0530 Subject: [PATCH 10/11] Removed solution for 1307. --- .../1307.Verbal Arithmetic Puzzle/README.md | 56 ------------------ .../README_EN.md | 57 +------------------ .../1307.Verbal Arithmetic Puzzle/Solution.py | 56 ------------------ 3 files changed, 1 insertion(+), 168 deletions(-) delete mode 100644 solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py diff --git a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md index 716480fb96f05..4c4659ecb9f0d 100644 --- a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md +++ b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README.md @@ -69,62 +69,6 @@ ```python -class Solution: - def isSolvable(self, words: List[str], result: str) -> bool: - if max(map(len, words)) > len( - result - ): # If any of the words are bigger than the result, it will be impossible to solve - return False - # Add the result to the list, this way we will only subtract values when it comes to the result word. - # Thus at every index, if the total is zero, then for that letter index the formulat is correct - words = [word[::-1] for word in words] + [result[::-1]] - values = {} # Mapping from letter to values - nums = [0] * 10 - - # i: word index, j: ltr index, total: total current Sum - def dfs(i, j, total): - if j == len( - result - ): # Reached end of the indecies for ltrs in all words (END) - return ( - total % 10 == 0 - ) # Checking to see if the total for the current character is correct or not - if i == len(words): # Checked ltr at index j for all the words - return total % 10 == 0 and dfs(0, j + 1, total // 10) - - if j >= len(words[i]): - return dfs(i + 1, j, total) - - if words[i][j] in values: - if ( - values[words[i][j]] == 0 - and j == len(words[i]) - 1 - and len(words[i]) > 1 - ): - return False - if i == len(words) - 1: - return dfs(i + 1, j, total - values[words[i][j]]) - else: - return dfs(i + 1, j, total + values[words[i][j]]) - else: - for val, isUsed in enumerate(nums): - if not isUsed and (val != 0 or j == 0 or j < len(words[i]) - 1): - values[words[i][j]] = val - nums[val] = True - - if i == len(words) - 1 and dfs( - i + 1, j, total - values[words[i][j]] - ): - return True - elif i < len(words) - 1 and dfs( - i + 1, j, total + values[words[i][j]] - ): - return True - - values.pop(words[i][j]) - nums[val] = False - - return dfs(0, 0, 0) ``` diff --git a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md index 7bfd90e001cb5..6fe660b2b7903 100644 --- a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md +++ b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/README_EN.md @@ -60,62 +60,7 @@ Note that two different characters cannot map to the same digit. ### **Python3** ```python -class Solution: - def isSolvable(self, words: List[str], result: str) -> bool: - if max(map(len, words)) > len( - result - ): # If any of the words are bigger than the result, it will be impossible to solve - return False - # Add the result to the list, this way we will only subtract values when it comes to the result word. - # Thus at every index, if the total is zero, then for that letter index the formulat is correct - words = [word[::-1] for word in words] + [result[::-1]] - values = {} # Mapping from letter to values - nums = [0] * 10 - - # i: word index, j: ltr index, total: total current Sum - def dfs(i, j, total): - if j == len( - result - ): # Reached end of the indecies for ltrs in all words (END) - return ( - total % 10 == 0 - ) # Checking to see if the total for the current character is correct or not - if i == len(words): # Checked ltr at index j for all the words - return total % 10 == 0 and dfs(0, j + 1, total // 10) - - if j >= len(words[i]): - return dfs(i + 1, j, total) - - if words[i][j] in values: - if ( - values[words[i][j]] == 0 - and j == len(words[i]) - 1 - and len(words[i]) > 1 - ): - return False - if i == len(words) - 1: - return dfs(i + 1, j, total - values[words[i][j]]) - else: - return dfs(i + 1, j, total + values[words[i][j]]) - else: - for val, isUsed in enumerate(nums): - if not isUsed and (val != 0 or j == 0 or j < len(words[i]) - 1): - values[words[i][j]] = val - nums[val] = True - - if i == len(words) - 1 and dfs( - i + 1, j, total - values[words[i][j]] - ): - return True - elif i < len(words) - 1 and dfs( - i + 1, j, total + values[words[i][j]] - ): - return True - - values.pop(words[i][j]) - nums[val] = False - - return dfs(0, 0, 0) + ``` ### **Java** diff --git a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py b/solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py deleted file mode 100644 index 53b0787aff3a6..0000000000000 --- a/solution/1300-1399/1307.Verbal Arithmetic Puzzle/Solution.py +++ /dev/null @@ -1,56 +0,0 @@ -class Solution: - def isSolvable(self, words: List[str], result: str) -> bool: - if max(map(len, words)) > len( - result - ): # If any of the words are bigger than the result, it will be impossible to solve - return False - # Add the result to the list, this way we will only subtract values when it comes to the result word. - # Thus at every index, if the total is zero, then for that letter index the formulat is correct - words = [word[::-1] for word in words] + [result[::-1]] - values = {} # Mapping from letter to values - nums = [0] * 10 - - # i: word index, j: ltr index, total: total current Sum - def dfs(i, j, total): - if j == len( - result - ): # Reached end of the indecies for ltrs in all words (END) - return ( - total % 10 == 0 - ) # Checking to see if the total for the current character is correct or not - if i == len(words): # Checked ltr at index j for all the words - return total % 10 == 0 and dfs(0, j + 1, total // 10) - - if j >= len(words[i]): - return dfs(i + 1, j, total) - - if words[i][j] in values: - if ( - values[words[i][j]] == 0 - and j == len(words[i]) - 1 - and len(words[i]) > 1 - ): - return False - if i == len(words) - 1: - return dfs(i + 1, j, total - values[words[i][j]]) - else: - return dfs(i + 1, j, total + values[words[i][j]]) - else: - for val, isUsed in enumerate(nums): - if not isUsed and (val != 0 or j == 0 or j < len(words[i]) - 1): - values[words[i][j]] = val - nums[val] = True - - if i == len(words) - 1 and dfs( - i + 1, j, total - values[words[i][j]] - ): - return True - elif i < len(words) - 1 and dfs( - i + 1, j, total + values[words[i][j]] - ): - return True - - values.pop(words[i][j]) - nums[val] = False - - return dfs(0, 0, 0) From 54ba9acdd2ae0eb3af8cc785f80fea5096011d17 Mon Sep 17 00:00:00 2001 From: Rhitik Date: Thu, 19 Oct 2023 19:04:26 +0530 Subject: [PATCH 11/11] Solution for 1728. --- .../1700-1799/1728.Cat and Mouse II/README.md | 70 +++++++++++++++++++ .../1728.Cat and Mouse II/README_EN.md | 70 +++++++++++++++++++ .../1728.Cat and Mouse II/Solution.py | 70 +++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 solution/1700-1799/1728.Cat and Mouse II/Solution.py diff --git a/solution/1700-1799/1728.Cat and Mouse II/README.md b/solution/1700-1799/1728.Cat and Mouse II/README.md index dc19968a0e962..5d62429fa9da2 100644 --- a/solution/1700-1799/1728.Cat and Mouse II/README.md +++ b/solution/1700-1799/1728.Cat and Mouse II/README.md @@ -105,6 +105,76 @@ ```python +class Solution: + def canMouseWin(self, grid: List[str], catJump: int, mouseJump: int) -> bool: + dirs = [0, 1, 0, -1, 0] + m = len(grid) + n = len(grid[0]) + nFloors = 0 + cat = 0 # cat's position + mouse = 0 # mouse's position + + def hash(i: int, j: int) -> int: + return i * n + j + + for i in range(m): + for j in range(n): + if grid[i][j] != "#": + nFloors += 1 + if grid[i][j] == "C": + cat = hash(i, j) + elif grid[i][j] == "M": + mouse = hash(i, j) + + # dp(i, j, k) := True if mouse can win w// + # Cat on (i // 8, i % 8), mouse on (j // 8, j % 8), and turns = k + @functools.lru_cache(None) + def dp(cat: int, mouse: int, turn: int) -> bool: + # We already search whole touchable grid + if turn == nFloors * 2: + return False + + if turn % 2 == 0: + # mouse's turn + i = mouse // n + j = mouse % n + for k in range(4): + for jump in range(mouseJump + 1): + x = i + dirs[k] * jump + y = j + dirs[k + 1] * jump + if x < 0 or x == m or y < 0 or y == n: + break + if grid[x][y] == "#": + break + if grid[x][y] == "F": # Mouse eats the food, so mouse win + return True + if dp(cat, hash(x, y), turn + 1): + return True + # Mouse can't win, so mouse lose + return False + else: + # cat's turn + i = cat // n + j = cat % n + for k in range(4): + for jump in range(catJump + 1): + x = i + dirs[k] * jump + y = j + dirs[k + 1] * jump + if x < 0 or x == m or y < 0 or y == n: + break + if grid[x][y] == "#": + break + if grid[x][y] == "F": # Cat eats the food, so mouse lose + return False + nextCat = hash(x, y) + if nextCat == mouse: # Cat catches mouse, so mouse lose + return False + if not dp(nextCat, mouse, turn + 1): + return False + # Cat can't win, so mouse win + return True + + return dp(cat, mouse, 0) ``` diff --git a/solution/1700-1799/1728.Cat and Mouse II/README_EN.md b/solution/1700-1799/1728.Cat and Mouse II/README_EN.md index 2c22b6bbd3361..beef115aeaae9 100644 --- a/solution/1700-1799/1728.Cat and Mouse II/README_EN.md +++ b/solution/1700-1799/1728.Cat and Mouse II/README_EN.md @@ -79,6 +79,76 @@ ### **Python3** ```python +class Solution: + def canMouseWin(self, grid: List[str], catJump: int, mouseJump: int) -> bool: + dirs = [0, 1, 0, -1, 0] + m = len(grid) + n = len(grid[0]) + nFloors = 0 + cat = 0 # cat's position + mouse = 0 # mouse's position + + def hash(i: int, j: int) -> int: + return i * n + j + + for i in range(m): + for j in range(n): + if grid[i][j] != "#": + nFloors += 1 + if grid[i][j] == "C": + cat = hash(i, j) + elif grid[i][j] == "M": + mouse = hash(i, j) + + # dp(i, j, k) := True if mouse can win w// + # Cat on (i // 8, i % 8), mouse on (j // 8, j % 8), and turns = k + @functools.lru_cache(None) + def dp(cat: int, mouse: int, turn: int) -> bool: + # We already search whole touchable grid + if turn == nFloors * 2: + return False + + if turn % 2 == 0: + # mouse's turn + i = mouse // n + j = mouse % n + for k in range(4): + for jump in range(mouseJump + 1): + x = i + dirs[k] * jump + y = j + dirs[k + 1] * jump + if x < 0 or x == m or y < 0 or y == n: + break + if grid[x][y] == "#": + break + if grid[x][y] == "F": # Mouse eats the food, so mouse win + return True + if dp(cat, hash(x, y), turn + 1): + return True + # Mouse can't win, so mouse lose + return False + else: + # cat's turn + i = cat // n + j = cat % n + for k in range(4): + for jump in range(catJump + 1): + x = i + dirs[k] * jump + y = j + dirs[k + 1] * jump + if x < 0 or x == m or y < 0 or y == n: + break + if grid[x][y] == "#": + break + if grid[x][y] == "F": # Cat eats the food, so mouse lose + return False + nextCat = hash(x, y) + if nextCat == mouse: # Cat catches mouse, so mouse lose + return False + if not dp(nextCat, mouse, turn + 1): + return False + # Cat can't win, so mouse win + return True + + return dp(cat, mouse, 0) ``` diff --git a/solution/1700-1799/1728.Cat and Mouse II/Solution.py b/solution/1700-1799/1728.Cat and Mouse II/Solution.py new file mode 100644 index 0000000000000..7154a272c06d1 --- /dev/null +++ b/solution/1700-1799/1728.Cat and Mouse II/Solution.py @@ -0,0 +1,70 @@ +class Solution: + def canMouseWin(self, grid: List[str], catJump: int, mouseJump: int) -> bool: + dirs = [0, 1, 0, -1, 0] + m = len(grid) + n = len(grid[0]) + nFloors = 0 + cat = 0 # cat's position + mouse = 0 # mouse's position + + def hash(i: int, j: int) -> int: + return i * n + j + + for i in range(m): + for j in range(n): + if grid[i][j] != "#": + nFloors += 1 + if grid[i][j] == "C": + cat = hash(i, j) + elif grid[i][j] == "M": + mouse = hash(i, j) + + # dp(i, j, k) := True if mouse can win w// + # Cat on (i // 8, i % 8), mouse on (j // 8, j % 8), and turns = k + @functools.lru_cache(None) + def dp(cat: int, mouse: int, turn: int) -> bool: + # We already search whole touchable grid + if turn == nFloors * 2: + return False + + if turn % 2 == 0: + # mouse's turn + i = mouse // n + j = mouse % n + for k in range(4): + for jump in range(mouseJump + 1): + x = i + dirs[k] * jump + y = j + dirs[k + 1] * jump + if x < 0 or x == m or y < 0 or y == n: + break + if grid[x][y] == "#": + break + if grid[x][y] == "F": # Mouse eats the food, so mouse win + return True + if dp(cat, hash(x, y), turn + 1): + return True + # Mouse can't win, so mouse lose + return False + else: + # cat's turn + i = cat // n + j = cat % n + for k in range(4): + for jump in range(catJump + 1): + x = i + dirs[k] * jump + y = j + dirs[k + 1] * jump + if x < 0 or x == m or y < 0 or y == n: + break + if grid[x][y] == "#": + break + if grid[x][y] == "F": # Cat eats the food, so mouse lose + return False + nextCat = hash(x, y) + if nextCat == mouse: # Cat catches mouse, so mouse lose + return False + if not dp(nextCat, mouse, turn + 1): + return False + # Cat can't win, so mouse win + return True + + return dp(cat, mouse, 0)