From 11d47761bb5fa96cc5951fc56e3605b9846697cf Mon Sep 17 00:00:00 2001 From: yanglbme Date: Sun, 17 Dec 2023 10:05:06 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.0748 No.0748.Shortest Completing Word --- .../0748.Shortest Completing Word/README.md | 250 +++++++++++------- .../README_EN.md | 250 +++++++++++------- .../Solution.cpp | 62 ++--- .../0748.Shortest Completing Word/Solution.go | 49 ++-- .../Solution.java | 67 +++-- .../0748.Shortest Completing Word/Solution.py | 35 +-- .../0748.Shortest Completing Word/Solution.rs | 31 +++ .../0748.Shortest Completing Word/Solution.ts | 30 +++ .../README_EN.md | 6 + 9 files changed, 465 insertions(+), 315 deletions(-) create mode 100644 solution/0700-0799/0748.Shortest Completing Word/Solution.rs create mode 100644 solution/0700-0799/0748.Shortest Completing Word/Solution.ts diff --git a/solution/0700-0799/0748.Shortest Completing Word/README.md b/solution/0700-0799/0748.Shortest Completing Word/README.md index 3392b5ea2aad0..f25b4ee1a2d6b 100644 --- a/solution/0700-0799/0748.Shortest Completing Word/README.md +++ b/solution/0700-0799/0748.Shortest Completing Word/README.md @@ -52,6 +52,14 @@ +**方法一:计数** + +我们先用哈希表或者一个长度为 $26$ 的数组 $cnt$ 统计字符串 `licensePlate` 中每个字母出现的次数,注意这里我们统一将字母转换为小写进行计数。 + +然后,我们遍历数组 `words` 中的每个单词 $w$,如果单词 $w$ 的长度比答案 $ans$ 的长度长,那么我们直接跳过该单词。否则,我们再用哈希表或者一个长度为 $26$ 的数组 $t$ 统计单词 $w$ 中每个字母出现的次数。如果对于任意一个字母,$t$ 中该字母出现的次数小于 $cnt$ 中该字母出现的次数,那么我们也可以直接跳过该单词。否则,我们就找到了一个满足条件的单词,我们更新答案 $ans$ 为当前单词 $w$。 + +时间复杂度 $O(n \times |\Sigma|)$,空间复杂度 $O(|\Sigma|)$,其中 $n$ 是数组 `words` 的长度,而 $\Sigma$ 是字符集,这里字符集为所有小写字母,因此 $|\Sigma| = 26$。 + ### **Python3** @@ -61,27 +69,14 @@ ```python class Solution: def shortestCompletingWord(self, licensePlate: str, words: List[str]) -> str: - def count(word): - counter = [0] * 26 - for c in word: - counter[ord(c) - ord('a')] += 1 - return counter - - def check(counter1, counter2): - for i in range(26): - if counter1[i] > counter2[i]: - return False - return True - - counter = count(c.lower() for c in licensePlate if c.isalpha()) - ans, n = None, 16 - for word in words: - if n <= len(word): + cnt = Counter(c.lower() for c in licensePlate if c.isalpha()) + ans = None + for w in words: + if ans and len(w) >= len(ans): continue - t = count(word) - if check(counter, t): - n = len(word) - ans = word + t = Counter(w) + if all(v <= t[c] for c, v in cnt.items()): + ans = w return ans ``` @@ -92,39 +87,34 @@ class Solution: ```java class Solution { public String shortestCompletingWord(String licensePlate, String[] words) { - int[] counter = count(licensePlate.toLowerCase()); - String ans = null; - int n = 16; - for (String word : words) { - if (n <= word.length()) { + int[] cnt = new int[26]; + for (int i = 0; i < licensePlate.length(); ++i) { + char c = licensePlate.charAt(i); + if (Character.isLetter(c)) { + cnt[Character.toLowerCase(c) - 'a']++; + } + } + String ans = ""; + for (String w : words) { + if (!ans.isEmpty() && w.length() >= ans.length()) { continue; } - int[] t = count(word); - if (check(counter, t)) { - n = word.length(); - ans = word; + int[] t = new int[26]; + for (int i = 0; i < w.length(); ++i) { + t[w.charAt(i) - 'a']++; } - } - return ans; - } - - private int[] count(String word) { - int[] counter = new int[26]; - for (char c : word.toCharArray()) { - if (Character.isLetter(c)) { - ++counter[c - 'a']; + boolean ok = true; + for (int i = 0; i < 26; ++i) { + if (t[i] < cnt[i]) { + ok = false; + break; + } } - } - return counter; - } - - private boolean check(int[] counter1, int[] counter2) { - for (int i = 0; i < 26; ++i) { - if (counter1[i] > counter2[i]) { - return false; + if (ok) { + ans = w; } } - return true; + return ans; } } ``` @@ -135,74 +125,138 @@ class Solution { class Solution { public: string shortestCompletingWord(string licensePlate, vector& words) { - vector counter = count(licensePlate); - int n = 16; + int cnt[26]{}; + for (char& c : licensePlate) { + if (isalpha(c)) { + ++cnt[tolower(c) - 'a']; + } + } string ans; - for (auto& word : words) { - if (n <= word.size()) continue; - vector t = count(word); - if (check(counter, t)) { - n = word.size(); - ans = word; + for (auto& w : words) { + if (ans.size() && ans.size() <= w.size()) { + continue; + } + int t[26]{}; + for (char& c : w) { + ++t[c - 'a']; + } + bool ok = true; + for (int i = 0; i < 26; ++i) { + if (cnt[i] > t[i]) { + ok = false; + break; + } + } + if (ok) { + ans = w; } } return ans; } - - vector count(string& word) { - vector counter(26); - for (char& c : word) - if (isalpha(c)) - ++counter[tolower(c) - 'a']; - return counter; - } - - bool check(vector& counter1, vector& counter2) { - for (int i = 0; i < 26; ++i) - if (counter1[i] > counter2[i]) - return false; - return true; - } }; ``` ### **Go** ```go -func shortestCompletingWord(licensePlate string, words []string) string { - count := func(word string) []int { - counter := make([]int, 26) - for _, c := range word { - if unicode.IsLetter(c) { - counter[c-'a']++ - } - } - return counter - } - - check := func(cnt1, cnt2 []int) bool { - for i := 0; i < 26; i++ { - if cnt1[i] > cnt2[i] { - return false - } +func shortestCompletingWord(licensePlate string, words []string) (ans string) { + cnt := [26]int{} + for _, c := range licensePlate { + if unicode.IsLetter(c) { + cnt[unicode.ToLower(c)-'a']++ } - return true } - - counter := count(strings.ToLower(licensePlate)) - var ans string - n := 16 - for _, word := range words { - if n <= len(word) { + for _, w := range words { + if len(ans) > 0 && len(ans) <= len(w) { continue } - t := count(word) - if check(counter, t) { - n = len(word) - ans = word + t := [26]int{} + for _, c := range w { + t[c-'a']++ + } + ok := true + for i, v := range cnt { + if t[i] < v { + ok = false + break + } + } + if ok { + ans = w } } - return ans + return +} +``` + +### **TypeScript** + +```ts +function shortestCompletingWord(licensePlate: string, words: string[]): string { + const cnt: number[] = Array(26).fill(0); + for (const c of licensePlate) { + const i = c.toLowerCase().charCodeAt(0) - 97; + if (0 <= i && i < 26) { + ++cnt[i]; + } + } + let ans = ''; + for (const w of words) { + if (ans.length && ans.length <= w.length) { + continue; + } + const t = Array(26).fill(0); + for (const c of w) { + ++t[c.charCodeAt(0) - 97]; + } + let ok = true; + for (let i = 0; i < 26; ++i) { + if (t[i] < cnt[i]) { + ok = false; + break; + } + } + if (ok) { + ans = w; + } + } + return ans; +} +``` + +### **Rust** + +```rust +impl Solution { + pub fn shortest_completing_word(license_plate: String, words: Vec) -> String { + let mut cnt = vec![0; 26]; + for c in license_plate.chars() { + if c.is_ascii_alphabetic() { + cnt[((c.to_ascii_lowercase() as u8) - b'a') as usize] += 1; + } + } + let mut ans = String::new(); + for w in words { + if !ans.is_empty() && w.len() >= ans.len() { + continue; + } + let mut t = vec![0; 26]; + for c in w.chars() { + t[((c as u8) - b'a') as usize] += 1; + } + let mut ok = true; + for i in 0..26 { + if t[i] < cnt[i] { + ok = false; + break; + } + } + if ok { + ans = w; + } + } + ans + } } ``` diff --git a/solution/0700-0799/0748.Shortest Completing Word/README_EN.md b/solution/0700-0799/0748.Shortest Completing Word/README_EN.md index 3cb6956f3fd3d..c4e611d0e741c 100644 --- a/solution/0700-0799/0748.Shortest Completing Word/README_EN.md +++ b/solution/0700-0799/0748.Shortest Completing Word/README_EN.md @@ -47,6 +47,14 @@ Since "steps" is the only word containing all the letters, that is the ## Solutions +**Solution 1: Counting** + +First, we use a hash table or an array $cnt$ of length $26$ to count the frequency of each letter in the string `licensePlate`. Note that we convert all letters to lowercase for counting. + +Then, we traverse each word $w$ in the array `words`. If the length of the word $w$ is longer than the length of the answer $ans$, we directly skip this word. Otherwise, we use another hash table or an array $t$ of length $26$ to count the frequency of each letter in the word $w$. If for any letter, the frequency of this letter in $t$ is less than the frequency of this letter in $cnt$, we can also directly skip this word. Otherwise, we have found a word that meets the conditions, and we update the answer $ans$ to the current word $w$. + +The time complexity is $O(n \times |\Sigma|)$, and the space complexity is $O(|\Sigma|)$. Here, $n$ is the length of the array `words`, and $\Sigma$ is the character set. In this case, the character set is all lowercase letters, so $|\Sigma| = 26$. + ### **Python3** @@ -54,27 +62,14 @@ Since "steps" is the only word containing all the letters, that is the ```python class Solution: def shortestCompletingWord(self, licensePlate: str, words: List[str]) -> str: - def count(word): - counter = [0] * 26 - for c in word: - counter[ord(c) - ord('a')] += 1 - return counter - - def check(counter1, counter2): - for i in range(26): - if counter1[i] > counter2[i]: - return False - return True - - counter = count(c.lower() for c in licensePlate if c.isalpha()) - ans, n = None, 16 - for word in words: - if n <= len(word): + cnt = Counter(c.lower() for c in licensePlate if c.isalpha()) + ans = None + for w in words: + if ans and len(w) >= len(ans): continue - t = count(word) - if check(counter, t): - n = len(word) - ans = word + t = Counter(w) + if all(v <= t[c] for c, v in cnt.items()): + ans = w return ans ``` @@ -83,39 +78,34 @@ class Solution: ```java class Solution { public String shortestCompletingWord(String licensePlate, String[] words) { - int[] counter = count(licensePlate.toLowerCase()); - String ans = null; - int n = 16; - for (String word : words) { - if (n <= word.length()) { + int[] cnt = new int[26]; + for (int i = 0; i < licensePlate.length(); ++i) { + char c = licensePlate.charAt(i); + if (Character.isLetter(c)) { + cnt[Character.toLowerCase(c) - 'a']++; + } + } + String ans = ""; + for (String w : words) { + if (!ans.isEmpty() && w.length() >= ans.length()) { continue; } - int[] t = count(word); - if (check(counter, t)) { - n = word.length(); - ans = word; + int[] t = new int[26]; + for (int i = 0; i < w.length(); ++i) { + t[w.charAt(i) - 'a']++; } - } - return ans; - } - - private int[] count(String word) { - int[] counter = new int[26]; - for (char c : word.toCharArray()) { - if (Character.isLetter(c)) { - ++counter[c - 'a']; + boolean ok = true; + for (int i = 0; i < 26; ++i) { + if (t[i] < cnt[i]) { + ok = false; + break; + } } - } - return counter; - } - - private boolean check(int[] counter1, int[] counter2) { - for (int i = 0; i < 26; ++i) { - if (counter1[i] > counter2[i]) { - return false; + if (ok) { + ans = w; } } - return true; + return ans; } } ``` @@ -126,74 +116,138 @@ class Solution { class Solution { public: string shortestCompletingWord(string licensePlate, vector& words) { - vector counter = count(licensePlate); - int n = 16; + int cnt[26]{}; + for (char& c : licensePlate) { + if (isalpha(c)) { + ++cnt[tolower(c) - 'a']; + } + } string ans; - for (auto& word : words) { - if (n <= word.size()) continue; - vector t = count(word); - if (check(counter, t)) { - n = word.size(); - ans = word; + for (auto& w : words) { + if (ans.size() && ans.size() <= w.size()) { + continue; + } + int t[26]{}; + for (char& c : w) { + ++t[c - 'a']; + } + bool ok = true; + for (int i = 0; i < 26; ++i) { + if (cnt[i] > t[i]) { + ok = false; + break; + } + } + if (ok) { + ans = w; } } return ans; } - - vector count(string& word) { - vector counter(26); - for (char& c : word) - if (isalpha(c)) - ++counter[tolower(c) - 'a']; - return counter; - } - - bool check(vector& counter1, vector& counter2) { - for (int i = 0; i < 26; ++i) - if (counter1[i] > counter2[i]) - return false; - return true; - } }; ``` ### **Go** ```go -func shortestCompletingWord(licensePlate string, words []string) string { - count := func(word string) []int { - counter := make([]int, 26) - for _, c := range word { - if unicode.IsLetter(c) { - counter[c-'a']++ - } - } - return counter - } - - check := func(cnt1, cnt2 []int) bool { - for i := 0; i < 26; i++ { - if cnt1[i] > cnt2[i] { - return false - } +func shortestCompletingWord(licensePlate string, words []string) (ans string) { + cnt := [26]int{} + for _, c := range licensePlate { + if unicode.IsLetter(c) { + cnt[unicode.ToLower(c)-'a']++ } - return true } - - counter := count(strings.ToLower(licensePlate)) - var ans string - n := 16 - for _, word := range words { - if n <= len(word) { + for _, w := range words { + if len(ans) > 0 && len(ans) <= len(w) { continue } - t := count(word) - if check(counter, t) { - n = len(word) - ans = word + t := [26]int{} + for _, c := range w { + t[c-'a']++ + } + ok := true + for i, v := range cnt { + if t[i] < v { + ok = false + break + } + } + if ok { + ans = w } } - return ans + return +} +``` + +### **TypeScript** + +```ts +function shortestCompletingWord(licensePlate: string, words: string[]): string { + const cnt: number[] = Array(26).fill(0); + for (const c of licensePlate) { + const i = c.toLowerCase().charCodeAt(0) - 97; + if (0 <= i && i < 26) { + ++cnt[i]; + } + } + let ans = ''; + for (const w of words) { + if (ans.length && ans.length <= w.length) { + continue; + } + const t = Array(26).fill(0); + for (const c of w) { + ++t[c.charCodeAt(0) - 97]; + } + let ok = true; + for (let i = 0; i < 26; ++i) { + if (t[i] < cnt[i]) { + ok = false; + break; + } + } + if (ok) { + ans = w; + } + } + return ans; +} +``` + +### **Rust** + +```rust +impl Solution { + pub fn shortest_completing_word(license_plate: String, words: Vec) -> String { + let mut cnt = vec![0; 26]; + for c in license_plate.chars() { + if c.is_ascii_alphabetic() { + cnt[((c.to_ascii_lowercase() as u8) - b'a') as usize] += 1; + } + } + let mut ans = String::new(); + for w in words { + if !ans.is_empty() && w.len() >= ans.len() { + continue; + } + let mut t = vec![0; 26]; + for c in w.chars() { + t[((c as u8) - b'a') as usize] += 1; + } + let mut ok = true; + for i in 0..26 { + if t[i] < cnt[i] { + ok = false; + break; + } + } + if ok { + ans = w; + } + } + ans + } } ``` diff --git a/solution/0700-0799/0748.Shortest Completing Word/Solution.cpp b/solution/0700-0799/0748.Shortest Completing Word/Solution.cpp index 0694afd751f49..c79c78bd37d6b 100644 --- a/solution/0700-0799/0748.Shortest Completing Word/Solution.cpp +++ b/solution/0700-0799/0748.Shortest Completing Word/Solution.cpp @@ -1,32 +1,32 @@ -class Solution { -public: - string shortestCompletingWord(string licensePlate, vector& words) { - vector counter = count(licensePlate); - int n = 16; - string ans; - for (auto& word : words) { - if (n <= word.size()) continue; - vector t = count(word); - if (check(counter, t)) { - n = word.size(); - ans = word; - } - } - return ans; - } - - vector count(string& word) { - vector counter(26); - for (char& c : word) - if (isalpha(c)) - ++counter[tolower(c) - 'a']; - return counter; - } - - bool check(vector& counter1, vector& counter2) { - for (int i = 0; i < 26; ++i) - if (counter1[i] > counter2[i]) - return false; - return true; - } +class Solution { +public: + string shortestCompletingWord(string licensePlate, vector& words) { + int cnt[26]{}; + for (char& c : licensePlate) { + if (isalpha(c)) { + ++cnt[tolower(c) - 'a']; + } + } + string ans; + for (auto& w : words) { + if (ans.size() && ans.size() <= w.size()) { + continue; + } + int t[26]{}; + for (char& c : w) { + ++t[c - 'a']; + } + bool ok = true; + for (int i = 0; i < 26; ++i) { + if (cnt[i] > t[i]) { + ok = false; + break; + } + } + if (ok) { + ans = w; + } + } + return ans; + } }; \ No newline at end of file diff --git a/solution/0700-0799/0748.Shortest Completing Word/Solution.go b/solution/0700-0799/0748.Shortest Completing Word/Solution.go index d3820f177d38e..4051ceedc6a4c 100644 --- a/solution/0700-0799/0748.Shortest Completing Word/Solution.go +++ b/solution/0700-0799/0748.Shortest Completing Word/Solution.go @@ -1,35 +1,28 @@ -func shortestCompletingWord(licensePlate string, words []string) string { - count := func(word string) []int { - counter := make([]int, 26) - for _, c := range word { - if unicode.IsLetter(c) { - counter[c-'a']++ - } - } - return counter - } - - check := func(cnt1, cnt2 []int) bool { - for i := 0; i < 26; i++ { - if cnt1[i] > cnt2[i] { - return false - } +func shortestCompletingWord(licensePlate string, words []string) (ans string) { + cnt := [26]int{} + for _, c := range licensePlate { + if unicode.IsLetter(c) { + cnt[unicode.ToLower(c)-'a']++ } - return true } - - counter := count(strings.ToLower(licensePlate)) - var ans string - n := 16 - for _, word := range words { - if n <= len(word) { + for _, w := range words { + if len(ans) > 0 && len(ans) <= len(w) { continue } - t := count(word) - if check(counter, t) { - n = len(word) - ans = word + t := [26]int{} + for _, c := range w { + t[c-'a']++ + } + ok := true + for i, v := range cnt { + if t[i] < v { + ok = false + break + } + } + if ok { + ans = w } } - return ans + return } \ No newline at end of file diff --git a/solution/0700-0799/0748.Shortest Completing Word/Solution.java b/solution/0700-0799/0748.Shortest Completing Word/Solution.java index 4efe1ccb4b2be..1338440a8bdcb 100644 --- a/solution/0700-0799/0748.Shortest Completing Word/Solution.java +++ b/solution/0700-0799/0748.Shortest Completing Word/Solution.java @@ -1,37 +1,32 @@ -class Solution { - public String shortestCompletingWord(String licensePlate, String[] words) { - int[] counter = count(licensePlate.toLowerCase()); - String ans = null; - int n = 16; - for (String word : words) { - if (n <= word.length()) { - continue; - } - int[] t = count(word); - if (check(counter, t)) { - n = word.length(); - ans = word; - } - } - return ans; - } - - private int[] count(String word) { - int[] counter = new int[26]; - for (char c : word.toCharArray()) { - if (Character.isLetter(c)) { - ++counter[c - 'a']; - } - } - return counter; - } - - private boolean check(int[] counter1, int[] counter2) { - for (int i = 0; i < 26; ++i) { - if (counter1[i] > counter2[i]) { - return false; - } - } - return true; - } +class Solution { + public String shortestCompletingWord(String licensePlate, String[] words) { + int[] cnt = new int[26]; + for (int i = 0; i < licensePlate.length(); ++i) { + char c = licensePlate.charAt(i); + if (Character.isLetter(c)) { + cnt[Character.toLowerCase(c) - 'a']++; + } + } + String ans = ""; + for (String w : words) { + if (!ans.isEmpty() && w.length() >= ans.length()) { + continue; + } + int[] t = new int[26]; + for (int i = 0; i < w.length(); ++i) { + t[w.charAt(i) - 'a']++; + } + boolean ok = true; + for (int i = 0; i < 26; ++i) { + if (t[i] < cnt[i]) { + ok = false; + break; + } + } + if (ok) { + ans = w; + } + } + return ans; + } } \ No newline at end of file diff --git a/solution/0700-0799/0748.Shortest Completing Word/Solution.py b/solution/0700-0799/0748.Shortest Completing Word/Solution.py index e7b9d91eb1e3d..02452f1fad5e5 100644 --- a/solution/0700-0799/0748.Shortest Completing Word/Solution.py +++ b/solution/0700-0799/0748.Shortest Completing Word/Solution.py @@ -1,24 +1,11 @@ -class Solution: - def shortestCompletingWord(self, licensePlate: str, words: List[str]) -> str: - def count(word): - counter = [0] * 26 - for c in word: - counter[ord(c) - ord('a')] += 1 - return counter - - def check(counter1, counter2): - for i in range(26): - if counter1[i] > counter2[i]: - return False - return True - - counter = count(c.lower() for c in licensePlate if c.isalpha()) - ans, n = None, 16 - for word in words: - if n <= len(word): - continue - t = count(word) - if check(counter, t): - n = len(word) - ans = word - return ans +class Solution: + def shortestCompletingWord(self, licensePlate: str, words: List[str]) -> str: + cnt = Counter(c.lower() for c in licensePlate if c.isalpha()) + ans = None + for w in words: + if ans and len(w) >= len(ans): + continue + t = Counter(w) + if all(v <= t[c] for c, v in cnt.items()): + ans = w + return ans diff --git a/solution/0700-0799/0748.Shortest Completing Word/Solution.rs b/solution/0700-0799/0748.Shortest Completing Word/Solution.rs new file mode 100644 index 0000000000000..b3d710e9cde07 --- /dev/null +++ b/solution/0700-0799/0748.Shortest Completing Word/Solution.rs @@ -0,0 +1,31 @@ +impl Solution { + pub fn shortest_completing_word(license_plate: String, words: Vec) -> String { + let mut cnt = vec![0; 26]; + for c in license_plate.chars() { + if c.is_ascii_alphabetic() { + cnt[((c.to_ascii_lowercase() as u8) - b'a') as usize] += 1; + } + } + let mut ans = String::new(); + for w in words { + if !ans.is_empty() && w.len() >= ans.len() { + continue; + } + let mut t = vec![0; 26]; + for c in w.chars() { + t[((c as u8) - b'a') as usize] += 1; + } + let mut ok = true; + for i in 0..26 { + if t[i] < cnt[i] { + ok = false; + break; + } + } + if ok { + ans = w; + } + } + ans + } +} diff --git a/solution/0700-0799/0748.Shortest Completing Word/Solution.ts b/solution/0700-0799/0748.Shortest Completing Word/Solution.ts new file mode 100644 index 0000000000000..bc56ab46807c1 --- /dev/null +++ b/solution/0700-0799/0748.Shortest Completing Word/Solution.ts @@ -0,0 +1,30 @@ +function shortestCompletingWord(licensePlate: string, words: string[]): string { + const cnt: number[] = Array(26).fill(0); + for (const c of licensePlate) { + const i = c.toLowerCase().charCodeAt(0) - 97; + if (0 <= i && i < 26) { + ++cnt[i]; + } + } + let ans = ''; + for (const w of words) { + if (ans.length && ans.length <= w.length) { + continue; + } + const t = Array(26).fill(0); + for (const c of w) { + ++t[c.charCodeAt(0) - 97]; + } + let ok = true; + for (let i = 0; i < 26; ++i) { + if (t[i] < cnt[i]) { + ok = false; + break; + } + } + if (ok) { + ans = w; + } + } + return ans; +} diff --git a/solution/0700-0799/0750.Number Of Corner Rectangles/README_EN.md b/solution/0700-0799/0750.Number Of Corner Rectangles/README_EN.md index 09d33e3f609cf..c7319e005b52b 100644 --- a/solution/0700-0799/0750.Number Of Corner Rectangles/README_EN.md +++ b/solution/0700-0799/0750.Number Of Corner Rectangles/README_EN.md @@ -46,6 +46,12 @@ ## Solutions +**Solution 1: Hash Table + Enumeration** + +We enumerate each row as the bottom of the rectangle. For the current row, if both column $i$ and column $j$ are $1$, then we use a hash table to find out how many of the previous rows have both columns $i$ and $j$ as $1$. This is the number of rectangles with $(i, j)$ as the bottom right corner, and we add this number to the answer. Then we add $(i, j)$ to the hash table and continue to enumerate the next pair $(i, j)$. + +The time complexity is $O(m \times n^2)$, and the space complexity is $O(n^2)$. Here, $m$ and $n$ are the number of rows and columns of the matrix, respectively. + ### **Python3**