Skip to content

feat: add solutions to lc problems: No.216,247,249 #2634

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

Merged
merged 1 commit into from
Apr 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 19 additions & 21 deletions solution/0200-0299/0216.Combination Sum III/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,6 @@
- 如果 $i \gt 9$ 或者 $i \gt s$ 或者当前搜索路径 $t$ 的长度大于 $k$,说明当前搜索路径不可能是答案,直接返回。
- 否则,我们可以选择将数字 $i$ 加入搜索路径 $t$ 中,然后继续搜索,即执行 $dfs(i + 1, s - i)$,搜索完成后,将 $i$ 从搜索路径 $t$ 中移除;我们也可以选择不将数字 $i$ 加入搜索路径 $t$ 中,直接执行 $dfs(i + 1, s)$。

方式二:

- 如果 $s = 0$,且当前搜索路径 $t$ 的长度为 $k$,说明找到了一组答案,将 $t$ 加入 $ans$ 中,然后返回。
- 如果 $i \gt 9$ 或者 $i \gt s$ 或者当前搜索路径 $t$ 的长度大于 $k$,说明当前搜索路径不可能是答案,直接返回。
- 否则,我们枚举下一个数字 $j$,即 $j \in [i, 9]$,将数字 $j$ 加入搜索路径 $t$ 中,然后继续搜索,即执行 $dfs(j + 1, s - j)$,搜索完成后,将 $j$ 从搜索路径 $t$ 中移除。

在主函数中,我们调用 $dfs(1, n)$,即从数字 $1$ 开始枚举,剩下和为 $n$ 的数字需要枚举。搜索完成后,即可得到所有的答案。

时间复杂度 $(C_{9}^k \times k)$,空间复杂度 $O(k)$。

<!-- tabs:start -->

```python
Expand Down Expand Up @@ -280,19 +270,15 @@ public class Solution {

<!-- tabs:end -->

### 方法二:二进制枚举

我们可以用一个长度为 $9$ 的二进制整数表示数字 $1$ 到 $9$ 的选取情况,其中二进制整数的第 $i$ 位表示数字 $i + 1$ 是否被选取,如果第 $i$ 位为 $1$,则表示数字 $i + 1$ 被选取,否则表示数字 $i + 1$ 没有被选取。

我们在 $[0, 2^9)$ 范围内枚举二进制整数,对于当前枚举到的二进制整数 $mask$,如果 $mask$ 的二进制表示中 $1$ 的个数为 $k$,且 $mask$ 的二进制表示中 $1$ 所对应的数字之和为 $n$,则说明 $mask$ 对应的数字选取方案是一组答案。我们将 $mask$ 对应的数字选取方案加入答案即可。
方式二:

时间复杂度 $O(2^9 \times 9)$,空间复杂度 $O(k)$。
- 如果 $s = 0$,且当前搜索路径 $t$ 的长度为 $k$,说明找到了一组答案,将 $t$ 加入 $ans$ 中,然后返回。
- 如果 $i \gt 9$ 或者 $i \gt s$ 或者当前搜索路径 $t$ 的长度大于 $k$,说明当前搜索路径不可能是答案,直接返回。
- 否则,我们枚举下一个数字 $j$,即 $j \in [i, 9]$,将数字 $j$ 加入搜索路径 $t$ 中,然后继续搜索,即执行 $dfs(j + 1, s - j)$,搜索完成后,将 $j$ 从搜索路径 $t$ 中移除。

相似题目:
在主函数中,我们调用 $dfs(1, n)$,即从数字 $1$ 开始枚举,剩下和为 $n$ 的数字需要枚举。搜索完成后,即可得到所有的答案。

- [39. 组合总和](https://github.com/doocs/leetcode/blob/main/solution/0000-0099/0039.Combination%20Sum/README.md)
- [40. 组合总和 II](https://github.com/doocs/leetcode/blob/main/solution/0000-0099/0040.Combination%20Sum%20II/README.md)
- [77. 组合](https://github.com/doocs/leetcode/blob/main/solution/0000-0099/0077.Combinations/README.md)
时间复杂度 $(C_{9}^k \times k)$,空间复杂度 $O(k)$。

<!-- tabs:start -->

Expand Down Expand Up @@ -459,7 +445,19 @@ public class Solution {

<!-- tabs:end -->

### 方法三
### 方法二:二进制枚举

我们可以用一个长度为 $9$ 的二进制整数表示数字 $1$ 到 $9$ 的选取情况,其中二进制整数的第 $i$ 位表示数字 $i + 1$ 是否被选取,如果第 $i$ 位为 $1$,则表示数字 $i + 1$ 被选取,否则表示数字 $i + 1$ 没有被选取。

我们在 $[0, 2^9)$ 范围内枚举二进制整数,对于当前枚举到的二进制整数 $mask$,如果 $mask$ 的二进制表示中 $1$ 的个数为 $k$,且 $mask$ 的二进制表示中 $1$ 所对应的数字之和为 $n$,则说明 $mask$ 对应的数字选取方案是一组答案。我们将 $mask$ 对应的数字选取方案加入答案即可。

时间复杂度 $O(2^9 \times 9)$,空间复杂度 $O(k)$。

相似题目:

- [39. 组合总和](https://github.com/doocs/leetcode/blob/main/solution/0000-0099/0039.Combination%20Sum/README.md)
- [40. 组合总和 II](https://github.com/doocs/leetcode/blob/main/solution/0000-0099/0040.Combination%20Sum%20II/README.md)
- [77. 组合](https://github.com/doocs/leetcode/blob/main/solution/0000-0099/0077.Combinations/README.md)

<!-- tabs:start -->

Expand Down
36 changes: 33 additions & 3 deletions solution/0200-0299/0216.Combination Sum III/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,17 @@ Using 4 different numbers in the range [1,9], the smallest sum we can get is 1+2

## Solutions

### Solution 1
### Solution 1: Pruning + Backtracking (Two Approaches)

We design a function $dfs(i, s)$, which represents that we are currently enumerating the number $i$, and there are still numbers with a sum of $s$ to be enumerated. The current search path is $t$, and the answer is $ans$.

The execution logic of the function $dfs(i, s)$ is as follows:

Approach One:

- If $s = 0$ and the length of the current search path $t$ is $k$, it means that a group of answers has been found. Add $t$ to $ans$ and then return.
- If $i \gt 9$ or $i \gt s$ or the length of the current search path $t$ is greater than $k$, it means that the current search path cannot be the answer, so return directly.
- Otherwise, we can choose to add the number $i$ to the search path $t$, and then continue to search, i.e., execute $dfs(i + 1, s - i)$. After the search is completed, remove $i$ from the search path $t$; we can also choose not to add the number $i$ to the search path $t$, and directly execute $dfs(i + 1, s)$.

<!-- tabs:start -->

Expand Down Expand Up @@ -257,7 +267,15 @@ public class Solution {

<!-- tabs:end -->

### Solution 2
Another approach:

- If $s = 0$ and the length of the current search path $t$ is $k$, it means that a group of answers has been found. Add $t$ to $ans$ and then return.
- If $i \gt 9$ or $i \gt s$ or the length of the current search path $t$ is greater than $k$, it means that the current search path cannot be the answer, so return directly.
- Otherwise, we enumerate the next number $j$, i.e., $j \in [i, 9]$, add the number $j$ to the search path $t$, and then continue to search, i.e., execute $dfs(j + 1, s - j)$. After the search is completed, remove $j$ from the search path $t$.

In the main function, we call $dfs(1, n)$, i.e., start enumerating from the number $1$, and the remaining numbers with a sum of $n$ need to be enumerated. After the search is completed, we can get all the answers.

The time complexity is $(C_{9}^k \times k)$, and the space complexity is $O(k)$.

<!-- tabs:start -->

Expand Down Expand Up @@ -424,7 +442,19 @@ public class Solution {

<!-- tabs:end -->

### Solution 3
### Solution 2: Binary Enumeration

We can use a binary integer of length $9$ to represent the selection of numbers $1$ to $9$, where the $i$-th bit of the binary integer represents whether the number $i + 1$ is selected. If the $i$-th bit is $1$, it means that the number $i + 1$ is selected, otherwise, it means that the number $i + 1$ is not selected.

We enumerate binary integers in the range of $[0, 2^9)$. For the currently enumerated binary integer $mask$, if the number of $1$s in the binary representation of $mask$ is $k$, and the sum of the numbers corresponding to $1$ in the binary representation of $mask$ is $n$, it means that the number selection scheme corresponding to $mask$ is a group of answers. We can add the number selection scheme corresponding to $mask$ to the answer.

The time complexity is $O(2^9 \times 9)$, and the space complexity is $O(k)$.

Similar problems:

- [39. Combination Sum](https://github.com/doocs/leetcode/blob/main/solution/0000-0099/0039.Combination%20Sum/README_EN.md)
- [40. Combination Sum II](https://github.com/doocs/leetcode/blob/main/solution/0000-0099/0040.Combination%20Sum%20II/README_EN.md)
- [77. Combinations](https://github.com/doocs/leetcode/blob/main/solution/0000-0099/0077.Combinations/README_EN.md)

<!-- tabs:start -->

Expand Down
4 changes: 2 additions & 2 deletions solution/0200-0299/0246.Strobogrammatic Number/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@

我们定义一个数组 $d$,其中 $d[i]$ 表示数字 $i$ 旋转 180° 之后的数字。如果 $d[i]$ 为 $-1$,表示数字 $i$ 不能旋转 180° 得到一个数字。

定义两个指针 $i$ 和 $j$,分别指向字符串的左右两端,然后不断向中间移动指针,判断 $d[num[i]]$ 和 $num[j]$ 是否相等,如果不相等,说明该字符串不是中心对称数 🔒,直接返回 $false$ 即可。如果 $i \gt j$,说明遍历完了字符串,返回 $true$。
定义两个指针 $i$ 和 $j$,分别指向字符串的左右两端,然后不断向中间移动指针,判断 $d[num[i]]$ 和 $num[j]$ 是否相等,如果不相等,说明该字符串不是中心对称数,直接返回 $false$ 即可。如果 $i \gt j$,说明遍历完了字符串,返回 $true$。

时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为字符串的长度
时间复杂度 $O(n)$,其中 $n$ 为字符串的长度。空间复杂度 $O(1)$。

<!-- tabs:start -->

Expand Down
8 changes: 7 additions & 1 deletion solution/0200-0299/0246.Strobogrammatic Number/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,13 @@

## Solutions

### Solution 1
### Solution 1: Two Pointers Simulation

We define an array $d$, where $d[i]$ represents the number after rotating the digit $i$ by 180°. If $d[i]$ is $-1$, it means that the digit $i$ cannot be rotated 180° to get a valid digit.

We define two pointers $i$ and $j$, pointing to the left and right ends of the string, respectively. Then we continuously move the pointers towards the center, checking whether $d[num[i]]$ and $num[j]$ are equal. If they are not equal, it means that the string is not a strobogrammatic number, and we can directly return $false$. If $i > j$, it means that we have traversed the entire string, and we return $true$.

The time complexity is $O(n)$, where $n$ is the length of the string. The space complexity is $O(1)$.

<!-- tabs:start -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@

相似题目:

- [248. 中心对称数 II 🔒I](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0248.Strobogrammatic%20Number%20III/README.md)
- [248. 中心对称数 III 🔒](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0248.Strobogrammatic%20Number%20III/README.md)

<!-- tabs:start -->

Expand Down
20 changes: 19 additions & 1 deletion solution/0200-0299/0247.Strobogrammatic Number II/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,25 @@

## Solutions

### Solution 1
### Solution 1: Recursion

If the length is $1$, then the strobogrammatic numbers are only $0, 1, 8$; if the length is $2$, then the strobogrammatic numbers are only $11, 69, 88, 96$.

We design a recursive function $dfs(u)$, which returns the strobogrammatic numbers of length $u$. The answer is $dfs(n)$.

If $u$ is $0$, return a list containing an empty string, i.e., `[""]`; if $u$ is $1$, return the list `["0", "1", "8"]`.

If $u$ is greater than $1$, we traverse all the strobogrammatic numbers of length $u - 2$. For each strobogrammatic number $v$, we add $1, 8, 6, 9$ to both sides of it, and we can get the strobogrammatic numbers of length `u`.

Note that if $u \neq n$, we can also add $0$ to both sides of the strobogrammatic number.

Finally, we return all the strobogrammatic numbers of length $n$.

The time complexity is $O(2^{n+2})$.

Similar problems:

- [248. Strobogrammatic Number III 🔒](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0248.Strobogrammatic%20Number%20III/README_EN.md)

<!-- tabs:start -->

Expand Down
22 changes: 21 additions & 1 deletion solution/0200-0299/0248.Strobogrammatic Number III/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,27 @@

## Solutions

### Solution 1
### Solution 1: Recursion

If the length is $1$, then the strobogrammatic numbers are only $0, 1, 8$; if the length is $2$, then the strobogrammatic numbers are only $11, 69, 88, 96$.

We design a recursive function $dfs(u)$, which returns the strobogrammatic numbers of length $u$.

If $u$ is $0$, return a list containing an empty string, i.e., `[""]`; if $u$ is $1$, return the list `["0", "1", "8"]`.

If $u$ is greater than $1$, we traverse all the strobogrammatic numbers of length $u - 2$. For each strobogrammatic number $v$, we add $1, 8, 6, 9$ to both sides of it, and we can get the strobogrammatic numbers of length $u$.

Note that if $u \neq n$, we can also add $0$ to both sides of the strobogrammatic number.

Let the lengths of $low$ and $high$ be $a$ and $b$ respectively.

Next, we traverse all lengths in the range $[a,..b]$. For each length $n$, we get all strobogrammatic numbers $dfs(n)$, and then check whether they are in the range $[low, high]$. If they are, we increment the answer.

The time complexity is $O(2^{n+2} \times \log n)$.

Similar problems:

- [247. Strobogrammatic Number II](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0247.Strobogrammatic%20Number%20II/README_EN.md)

<!-- tabs:start -->

Expand Down
85 changes: 48 additions & 37 deletions solution/0200-0299/0249.Group Shifted Strings/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,45 +30,50 @@

## 解法

### 方法一
### 方法一:哈希表

我们用一个哈希表 $g$ 来存储每个字符串移位后且首位为 '`a`' 的字符串。即 $g[t]$ 表示所有字符串移位后字符串为 $t$ 的字符串集合。

我们遍历每个字符串,对于每个字符串,我们计算其移位后的字符串 $t$,然后将其加入到 $g[t]$ 中。

最后,我们将 $g$ 中的所有值取出来,即为答案。

时间复杂度 $O(L)$,空间复杂度 $O(L)$,其中 $L$ 为所有字符串的长度之和。

<!-- tabs:start -->

```python
class Solution:
def groupStrings(self, strings: List[str]) -> List[List[str]]:
mp = defaultdict(list)
g = defaultdict(list)
for s in strings:
diff = ord(s[0]) - ord("a")
t = []
diff = ord(s[0]) - ord('a')
for c in s:
d = ord(c) - diff
if d < ord('a'):
d += 26
t.append(chr(d))
k = ''.join(t)
mp[k].append(s)
return list(mp.values())
c = ord(c) - diff
if c < ord("a"):
c += 26
t.append(chr(c))
g["".join(t)].append(s)
return list(g.values())
```

```java
class Solution {
public List<List<String>> groupStrings(String[] strings) {
Map<String, List<String>> mp = new HashMap<>();
for (String s : strings) {
int diff = s.charAt(0) - 'a';
Map<String, List<String>> g = new HashMap<>();
for (var s : strings) {
char[] t = s.toCharArray();
int diff = t[0] - 'a';
for (int i = 0; i < t.length; ++i) {
char d = (char) (t[i] - diff);
if (d < 'a') {
d += 26;
t[i] = (char) (t[i] - diff);
if (t[i] < 'a') {
t[i] += 26;
}
t[i] = d;
}
String key = new String(t);
mp.computeIfAbsent(key, k -> new ArrayList<>()).add(s);
g.computeIfAbsent(new String(t), k -> new ArrayList<>()).add(s);
}
return new ArrayList<>(mp.values());
return new ArrayList<>(g.values());
}
}
```
Expand All @@ -77,38 +82,44 @@ class Solution {
class Solution {
public:
vector<vector<string>> groupStrings(vector<string>& strings) {
unordered_map<string, vector<string>> mp;
unordered_map<string, vector<string>> g;
for (auto& s : strings) {
string t;
int diff = s[0] - 'a';
string t = s;
for (int i = 0; i < t.size(); ++i) {
char d = t[i] - diff;
if (d < 'a') d += 26;
t[i] = d;
for (int i = 0; i < s.size(); ++i) {
char c = s[i] - diff;
if (c < 'a') {
c += 26;
}
t.push_back(c);
}
cout << t << endl;
mp[t].push_back(s);
g[t].emplace_back(s);
}
vector<vector<string>> ans;
for (auto& e : mp)
ans.push_back(e.second);
for (auto& p : g) {
ans.emplace_back(move(p.second));
}
return ans;
}
};
```

```go
func groupStrings(strings []string) [][]string {
mp := make(map[string][]string)
g := make(map[string][]string)
for _, s := range strings {
k := ""
for i := range s {
k += string((s[i]-s[0]+26)%26 + 'a')
t := []byte(s)
diff := t[0] - 'a'
for i := range t {
t[i] -= diff
if t[i] < 'a' {
t[i] += 26
}
}
mp[k] = append(mp[k], s)
g[string(t)] = append(g[string(t)], s)
}
var ans [][]string
for _, v := range mp {
ans := make([][]string, 0, len(g))
for _, v := range g {
ans = append(ans, v)
}
return ans
Expand Down
Loading