diff --git a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/README.md b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/README.md index 4729951172038..1ef619a84a80f 100644 --- a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/README.md +++ b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/README.md @@ -68,9 +68,11 @@ tags: ### 方法一:哈希表 -遍历字符串 $s$,用一个哈希表存储所有长度为 $k$ 的不同子串。只需要判断子串数能否达到 $2^k$ 即可。 +首先,对于一个长度为 $n$ 的字符串 $s$,长度为 $k$ 的子串的个数为 $n - k + 1$,如果 $n - k + 1 < 2^k$,则一定存在长度为 $k$ 的二进制串不是 $s$ 的子串,返回 `false`。 -时间复杂度 $O(n \times k)$,其中 $n$ 是字符串 $s$ 的长度,$k$ 是子串长度。 +接下来,我们遍历字符串 $s$,将所有长度为 $k$ 的子串存入集合 $ss$,最后判断集合 $ss$ 的大小是否等于 $2^k$。 + +时间复杂度 $O(n \times k)$,空间复杂度 $O(n)$。其中 $n$ 是字符串 $s$ 的长度。 @@ -79,8 +81,12 @@ tags: ```python class Solution: def hasAllCodes(self, s: str, k: int) -> bool: - ss = {s[i : i + k] for i in range(len(s) - k + 1)} - return len(ss) == 1 << k + n = len(s) + m = 1 << k + if n - k + 1 < m: + return False + ss = {s[i : i + k] for i in range(n - k + 1)} + return len(ss) == m ``` #### Java @@ -88,11 +94,16 @@ class Solution: ```java class Solution { public boolean hasAllCodes(String s, int k) { + int n = s.length(); + int m = 1 << k; + if (n - k + 1 < m) { + return false; + } Set ss = new HashSet<>(); - for (int i = 0; i < s.length() - k + 1; ++i) { + for (int i = 0; i < n - k + 1; ++i) { ss.add(s.substring(i, i + k)); } - return ss.size() == 1 << k; + return ss.size() == m; } } ``` @@ -103,11 +114,16 @@ class Solution { class Solution { public: bool hasAllCodes(string s, int k) { + int n = s.size(); + int m = 1 << k; + if (n - k + 1 < m) { + return false; + } unordered_set ss; - for (int i = 0; i + k <= s.size(); ++i) { + for (int i = 0; i + k <= n; ++i) { ss.insert(move(s.substr(i, k))); } - return ss.size() == 1 << k; + return ss.size() == m; } }; ``` @@ -116,11 +132,32 @@ public: ```go func hasAllCodes(s string, k int) bool { + n, m := len(s), 1<(); + for (let i = 0; i + k <= n; ++i) { + ss.add(s.slice(i, i + k)); + } + return ss.size === m; } ``` @@ -132,9 +169,9 @@ func hasAllCodes(s string, k int) bool { ### 方法二:滑动窗口 -方法一中,我们存储了所有长度为 $k$ 的不同子串,子串的处理需要 $O(k)$ 的时间,我们可以改用滑动窗口,每次添加最新字符时,删除窗口最左边的字符。此过程中用一个整型数字 $num$ 来存放子串。 +方法一中,我们存储了所有长度为 $k$ 的不同子串,子串的处理需要 $O(k)$ 的时间,我们可以改用滑动窗口,每次添加最新字符时,删除窗口最左边的字符。此过程中用一个整型数字 $x$ 来存放子串。 -时间复杂度 $O(n)$,其中 $n$ 是字符串 $s$ 的长度。 +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是字符串 $s$ 的长度。 @@ -143,17 +180,19 @@ func hasAllCodes(s string, k int) bool { ```python class Solution: def hasAllCodes(self, s: str, k: int) -> bool: - if len(s) - k + 1 < (1 << k): + n = len(s) + m = 1 << k + if n - k + 1 < m: return False - vis = [False] * (1 << k) - num = int(s[:k], 2) - vis[num] = True - for i in range(k, len(s)): - a = (ord(s[i - k]) - ord('0')) << (k - 1) - b = ord(s[i]) - ord('0') - num = ((num - a) << 1) + b - vis[num] = True - return all(v for v in vis) + ss = set() + x = int(s[:k], 2) + ss.add(x) + for i in range(k, n): + a = int(s[i - k]) << (k - 1) + b = int(s[i]) + x = (x - a) << 1 | b + ss.add(x) + return len(ss) == m ``` #### Java @@ -162,19 +201,20 @@ class Solution: class Solution { public boolean hasAllCodes(String s, int k) { int n = s.length(); - if (n - k + 1 < (1 << k)) { + int m = 1 << k; + if (n - k + 1 < m) { return false; } - boolean[] vis = new boolean[1 << k]; - int num = Integer.parseInt(s.substring(0, k), 2); - vis[num] = true; + boolean[] ss = new boolean[m]; + int x = Integer.parseInt(s.substring(0, k), 2); + ss[x] = true; for (int i = k; i < n; ++i) { int a = (s.charAt(i - k) - '0') << (k - 1); int b = s.charAt(i) - '0'; - num = (num - a) << 1 | b; - vis[num] = true; + x = (x - a) << 1 | b; + ss[x] = true; } - for (boolean v : vis) { + for (boolean v : ss) { if (!v) { return false; } @@ -191,19 +231,21 @@ class Solution { public: bool hasAllCodes(string s, int k) { int n = s.size(); - if (n - k + 1 < (1 << k)) return false; - vector vis(1 << k); - int num = stoi(s.substr(0, k), nullptr, 2); - vis[num] = true; + int m = 1 << k; + if (n - k + 1 < m) { + return false; + } + bool ss[m]; + memset(ss, false, sizeof(ss)); + int x = stoi(s.substr(0, k), nullptr, 2); + ss[x] = true; for (int i = k; i < n; ++i) { int a = (s[i - k] - '0') << (k - 1); int b = s[i] - '0'; - num = (num - a) << 1 | b; - vis[num] = true; + x = (x - a) << 1 | b; + ss[x] = true; } - for (bool v : vis) - if (!v) return false; - return true; + return all_of(ss, ss + m, [](bool v) { return v; }); } }; ``` @@ -212,22 +254,20 @@ public: ```go func hasAllCodes(s string, k int) bool { - n := len(s) - if n-k+1 < (1 << k) { + n, m := len(s), 1<(); + ss.add(x); + for (let i = k; i < n; ++i) { + const a = +s[i - k] << (k - 1); + const b = +s[i]; + x = ((x - a) << 1) | b; + ss.add(x); + } + return ss.size === m; +} +``` + diff --git a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/README_EN.md b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/README_EN.md index 599fbce9fc112..87589a130ad6a 100644 --- a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/README_EN.md +++ b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/README_EN.md @@ -38,7 +38,7 @@ tags:
 Input: s = "0110", k = 1
 Output: true
-Explanation: The binary codes of length 1 are "0" and "1", it is clear that both exist as a substring. 
+Explanation: The binary codes of length 1 are "0" and "1", it is clear that both exist as a substring.
 

Example 3:

@@ -64,7 +64,13 @@ tags: -### Solution 1 +### Solution 1: Hash Table + +First, for a string $s$ of length $n$, the number of substrings of length $k$ is $n - k + 1$. If $n - k + 1 < 2^k$, then there must exist a binary string of length $k$ that is not a substring of $s$, so we return `false`. + +Next, we traverse the string $s$ and store all substrings of length $k$ in a set $ss$. Finally, we check if the size of the set $ss$ is equal to $2^k$. + +The time complexity is $O(n \times k)$, and the space complexity is $O(n)$. Here, $n$ is the length of the string $s$. @@ -73,8 +79,12 @@ tags: ```python class Solution: def hasAllCodes(self, s: str, k: int) -> bool: - ss = {s[i : i + k] for i in range(len(s) - k + 1)} - return len(ss) == 1 << k + n = len(s) + m = 1 << k + if n - k + 1 < m: + return False + ss = {s[i : i + k] for i in range(n - k + 1)} + return len(ss) == m ``` #### Java @@ -82,11 +92,16 @@ class Solution: ```java class Solution { public boolean hasAllCodes(String s, int k) { + int n = s.length(); + int m = 1 << k; + if (n - k + 1 < m) { + return false; + } Set ss = new HashSet<>(); - for (int i = 0; i < s.length() - k + 1; ++i) { + for (int i = 0; i < n - k + 1; ++i) { ss.add(s.substring(i, i + k)); } - return ss.size() == 1 << k; + return ss.size() == m; } } ``` @@ -97,11 +112,16 @@ class Solution { class Solution { public: bool hasAllCodes(string s, int k) { + int n = s.size(); + int m = 1 << k; + if (n - k + 1 < m) { + return false; + } unordered_set ss; - for (int i = 0; i + k <= s.size(); ++i) { + for (int i = 0; i + k <= n; ++i) { ss.insert(move(s.substr(i, k))); } - return ss.size() == 1 << k; + return ss.size() == m; } }; ``` @@ -110,11 +130,32 @@ public: ```go func hasAllCodes(s string, k int) bool { + n, m := len(s), 1<(); + for (let i = 0; i + k <= n; ++i) { + ss.add(s.slice(i, i + k)); + } + return ss.size === m; } ``` @@ -124,7 +165,11 @@ func hasAllCodes(s string, k int) bool { -### Solution 2 +### Solution 2: Sliding Window + +In Solution 1, we stored all distinct substrings of length $k$, and processing each substring requires $O(k)$ time. We can instead use a sliding window, where each time we add the latest character, we remove the leftmost character from the window. During this process, we use an integer $x$ to store the substring. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the string $s$. @@ -133,17 +178,19 @@ func hasAllCodes(s string, k int) bool { ```python class Solution: def hasAllCodes(self, s: str, k: int) -> bool: - if len(s) - k + 1 < (1 << k): + n = len(s) + m = 1 << k + if n - k + 1 < m: return False - vis = [False] * (1 << k) - num = int(s[:k], 2) - vis[num] = True - for i in range(k, len(s)): - a = (ord(s[i - k]) - ord('0')) << (k - 1) - b = ord(s[i]) - ord('0') - num = ((num - a) << 1) + b - vis[num] = True - return all(v for v in vis) + ss = set() + x = int(s[:k], 2) + ss.add(x) + for i in range(k, n): + a = int(s[i - k]) << (k - 1) + b = int(s[i]) + x = (x - a) << 1 | b + ss.add(x) + return len(ss) == m ``` #### Java @@ -152,19 +199,20 @@ class Solution: class Solution { public boolean hasAllCodes(String s, int k) { int n = s.length(); - if (n - k + 1 < (1 << k)) { + int m = 1 << k; + if (n - k + 1 < m) { return false; } - boolean[] vis = new boolean[1 << k]; - int num = Integer.parseInt(s.substring(0, k), 2); - vis[num] = true; + boolean[] ss = new boolean[m]; + int x = Integer.parseInt(s.substring(0, k), 2); + ss[x] = true; for (int i = k; i < n; ++i) { int a = (s.charAt(i - k) - '0') << (k - 1); int b = s.charAt(i) - '0'; - num = (num - a) << 1 | b; - vis[num] = true; + x = (x - a) << 1 | b; + ss[x] = true; } - for (boolean v : vis) { + for (boolean v : ss) { if (!v) { return false; } @@ -181,19 +229,21 @@ class Solution { public: bool hasAllCodes(string s, int k) { int n = s.size(); - if (n - k + 1 < (1 << k)) return false; - vector vis(1 << k); - int num = stoi(s.substr(0, k), nullptr, 2); - vis[num] = true; + int m = 1 << k; + if (n - k + 1 < m) { + return false; + } + bool ss[m]; + memset(ss, false, sizeof(ss)); + int x = stoi(s.substr(0, k), nullptr, 2); + ss[x] = true; for (int i = k; i < n; ++i) { int a = (s[i - k] - '0') << (k - 1); int b = s[i] - '0'; - num = (num - a) << 1 | b; - vis[num] = true; + x = (x - a) << 1 | b; + ss[x] = true; } - for (bool v : vis) - if (!v) return false; - return true; + return all_of(ss, ss + m, [](bool v) { return v; }); } }; ``` @@ -202,22 +252,20 @@ public: ```go func hasAllCodes(s string, k int) bool { - n := len(s) - if n-k+1 < (1 << k) { + n, m := len(s), 1<(); + ss.add(x); + for (let i = k; i < n; ++i) { + const a = +s[i - k] << (k - 1); + const b = +s[i]; + x = ((x - a) << 1) | b; + ss.add(x); + } + return ss.size === m; +} +``` + diff --git a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.cpp b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.cpp index 4018b4114dfef..c6a2187424827 100644 --- a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.cpp +++ b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.cpp @@ -1,10 +1,15 @@ class Solution { public: bool hasAllCodes(string s, int k) { + int n = s.size(); + int m = 1 << k; + if (n - k + 1 < m) { + return false; + } unordered_set ss; - for (int i = 0; i + k <= s.size(); ++i) { + for (int i = 0; i + k <= n; ++i) { ss.insert(move(s.substr(i, k))); } - return ss.size() == 1 << k; + return ss.size() == m; } -}; \ No newline at end of file +}; diff --git a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.go b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.go index 2852e51db7b2a..84dee7d873f99 100644 --- a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.go +++ b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.go @@ -1,7 +1,11 @@ func hasAllCodes(s string, k int) bool { + n, m := len(s), 1< ss = new HashSet<>(); - for (int i = 0; i < s.length() - k + 1; ++i) { + for (int i = 0; i < n - k + 1; ++i) { ss.add(s.substring(i, i + k)); } - return ss.size() == 1 << k; + return ss.size() == m; } -} \ No newline at end of file +} diff --git a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.py b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.py index 5fba4d31a1744..1ef979e49c0ec 100644 --- a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.py +++ b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.py @@ -1,4 +1,8 @@ class Solution: def hasAllCodes(self, s: str, k: int) -> bool: - ss = {s[i : i + k] for i in range(len(s) - k + 1)} - return len(ss) == 1 << k + n = len(s) + m = 1 << k + if n - k + 1 < m: + return False + ss = {s[i : i + k] for i in range(n - k + 1)} + return len(ss) == m diff --git a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.ts b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.ts new file mode 100644 index 0000000000000..870b869f47320 --- /dev/null +++ b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution.ts @@ -0,0 +1,12 @@ +function hasAllCodes(s: string, k: number): boolean { + const n = s.length; + const m = 1 << k; + if (n - k + 1 < m) { + return false; + } + const ss = new Set(); + for (let i = 0; i + k <= n; ++i) { + ss.add(s.slice(i, i + k)); + } + return ss.size === m; +} diff --git a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.cpp b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.cpp index fa82b12a07c58..b364fa6c1644a 100644 --- a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.cpp +++ b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.cpp @@ -2,18 +2,20 @@ class Solution { public: bool hasAllCodes(string s, int k) { int n = s.size(); - if (n - k + 1 < (1 << k)) return false; - vector vis(1 << k); - int num = stoi(s.substr(0, k), nullptr, 2); - vis[num] = true; + int m = 1 << k; + if (n - k + 1 < m) { + return false; + } + bool ss[m]; + memset(ss, false, sizeof(ss)); + int x = stoi(s.substr(0, k), nullptr, 2); + ss[x] = true; for (int i = k; i < n; ++i) { int a = (s[i - k] - '0') << (k - 1); int b = s[i] - '0'; - num = (num - a) << 1 | b; - vis[num] = true; + x = (x - a) << 1 | b; + ss[x] = true; } - for (bool v : vis) - if (!v) return false; - return true; + return all_of(ss, ss + m, [](bool v) { return v; }); } -}; \ No newline at end of file +}; diff --git a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.go b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.go index ba3f68b1fe399..ad59761d8526a 100644 --- a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.go +++ b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.go @@ -1,23 +1,21 @@ func hasAllCodes(s string, k int) bool { - n := len(s) - if n-k+1 < (1 << k) { + n, m := len(s), 1< bool: - if len(s) - k + 1 < (1 << k): + n = len(s) + m = 1 << k + if n - k + 1 < m: return False - vis = [False] * (1 << k) - num = int(s[:k], 2) - vis[num] = True - for i in range(k, len(s)): - a = (ord(s[i - k]) - ord('0')) << (k - 1) - b = ord(s[i]) - ord('0') - num = ((num - a) << 1) + b - vis[num] = True - return all(v for v in vis) + ss = set() + x = int(s[:k], 2) + ss.add(x) + for i in range(k, n): + a = int(s[i - k]) << (k - 1) + b = int(s[i]) + x = (x - a) << 1 | b + ss.add(x) + return len(ss) == m diff --git a/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.ts b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.ts new file mode 100644 index 0000000000000..3070c56d1cd64 --- /dev/null +++ b/solution/1400-1499/1461.Check If a String Contains All Binary Codes of Size K/Solution2.ts @@ -0,0 +1,17 @@ +function hasAllCodes(s: string, k: number): boolean { + const n = s.length; + const m = 1 << k; + if (n - k + 1 < m) { + return false; + } + let x = +`0b${s.slice(0, k)}`; + const ss = new Set(); + ss.add(x); + for (let i = k; i < n; ++i) { + const a = +s[i - k] << (k - 1); + const b = +s[i]; + x = ((x - a) << 1) | b; + ss.add(x); + } + return ss.size === m; +} diff --git a/solution/1400-1499/1462.Course Schedule IV/README.md b/solution/1400-1499/1462.Course Schedule IV/README.md index d662b1c7ad2f7..9eecda829e104 100644 --- a/solution/1400-1499/1462.Course Schedule IV/README.md +++ b/solution/1400-1499/1462.Course Schedule IV/README.md @@ -233,7 +233,7 @@ function checkIfPrerequisite(n: number, prerequisites: number[][], queries: numb 在计算完所有节点对之间的可达性之后,对于每一个查询 $[a, b]$,我们直接返回 $f[a][b]$ 即可。 -时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 为节点数。 +时间复杂度 $O(n^3)$,空间复杂度 $O(n^2)$。其中 $n$ 为节点数。 diff --git a/solution/1400-1499/1462.Course Schedule IV/README_EN.md b/solution/1400-1499/1462.Course Schedule IV/README_EN.md index 80fff691fe917..8f05842d9bb4f 100644 --- a/solution/1400-1499/1462.Course Schedule IV/README_EN.md +++ b/solution/1400-1499/1462.Course Schedule IV/README_EN.md @@ -80,7 +80,19 @@ Course 0 is not a prerequisite of course 1, but the opposite is true. -### Solution 1 +### Solution 1: Floyd's Algorithm + +We create a 2D array $f$, where $f[i][j]$ indicates whether node $i$ can reach node $j$. + +Next, we iterate through the prerequisites array $prerequisites$. For each item $[a, b]$ in it, we set $f[a][b]$ to $true$. + +Then, we use Floyd's algorithm to compute the reachability between all pairs of nodes. + +Specifically, we use three nested loops: first enumerating the intermediate node $k$, then the starting node $i$, and finally the ending node $j$. For each iteration, if node $i$ can reach node $k$ and node $k$ can reach node $j$, then node $i$ can also reach node $j$, and we set $f[i][j]$ to $true$. + +After computing the reachability between all pairs of nodes, for each query $[a, b]$, we can directly return $f[a][b]$. + +The time complexity is $O(n^3)$, and the space complexity is $O(n^2)$, where $n$ is the number of nodes. @@ -202,7 +214,19 @@ function checkIfPrerequisite(n: number, prerequisites: number[][], queries: numb -### Solution 2 +### Solution 2: Topological Sorting + +Similar to Solution 1, we create a 2D array $f$, where $f[i][j]$ indicates whether node $i$ can reach node $j$. Additionally, we create an adjacency list $g$, where $g[i]$ represents all successor nodes of node $i$, and an array $indeg$, where $indeg[i]$ represents the in-degree of node $i$. + +Next, we iterate through the prerequisites array $prerequisites$. For each item $[a, b]$ in it, we update the adjacency list $g$ and the in-degree array $indeg$. + +Then, we use topological sorting to compute the reachability between all pairs of nodes. + +We define a queue $q$, initially adding all nodes with an in-degree of $0$ to the queue. Then, we continuously perform the following operations: remove the front node $i$ from the queue, then iterate through all nodes $j$ in $g[i]$, setting $f[i][j]$ to $true$. Next, we enumerate node $h$, and if $f[h][i]$ is $true$, we also set $f[h][j]$ to $true$. After this, we decrease the in-degree of $j$ by $1$. If the in-degree of $j$ becomes $0$, we add $j$ to the queue. + +After computing the reachability between all pairs of nodes, for each query $[a, b]$, we can directly return $f[a][b]$. + +The time complexity is $O(n^3)$, and the space complexity is $O(n^2)$, where $n$ is the number of nodes.