Skip to content

Commit 9103631

Browse files
committed
✨feat: add 93、95、1775
1 parent 1c742ca commit 9103631

6 files changed

+445
-12
lines changed

Index/二叉树.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
| 题目 | 题解 | 难度 | 推荐指数 |
22
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- |
3+
| [95. 不同的二叉搜索树 II](https://leetcode.cn/problems/unique-binary-search-trees-ii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/solution/gong-shui-san-xie-yi-ti-san-jie-pai-xu-y-8uah/) | 中等 | 🤩🤩🤩🤩 |
34
| [230. 二叉搜索树中第K小的元素](https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/solution/gong-shui-san-xie-yi-ti-san-jie-pai-xu-y-8uah/) | 中等 | 🤩🤩🤩🤩 |
45
| [240. 搜索二维矩阵 II](https://leetcode-cn.com/problems/search-a-2d-matrix-ii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/search-a-2d-matrix-ii/solution/gong-shui-san-xie-yi-ti-shuang-jie-er-fe-y1ns/) | 中等 | 🤩🤩🤩🤩🤩 |
56
| [297. 二叉树的序列化与反序列化](https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/xu-lie-hua-er-cha-shu-lcof/solution/gong-shui-san-xie-er-cha-shu-de-xu-lie-h-n89a/) | 困难 | 🤩🤩🤩🤩🤩 |

LeetCode/1741-1750/1743. 从相邻元素对还原数组(中等).md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ Tag : 「哈希表」、「双指针」、「模拟」
66

77

88

9-
存在一个由 n 个不同元素组成的整数数组 nums ,但你已经记不清具体内容。好在你还记得 nums 中的每一对相邻元素。
9+
存在一个由 `n` 个不同元素组成的整数数组 `nums` ,但你已经记不清具体内容。好在你还记得 `nums` 中的每一对相邻元素。
1010

11-
给你一个二维整数数组 adjacentPairs ,大小为 n - 1 ,其中每个 adjacentPairs[i] = [ui, vi] 表示元素 uivi 在 nums 中相邻。
11+
给你一个二维整数数组 `adjacentPairs` ,大小为 `n - 1` ,其中每个 $adjacentPairs[i] = [u_i, v_i]$ 表示元素 $u_i$$v_i$`nums` 中相邻。
1212

13-
题目数据保证所有由元素 nums[i] 和 nums[i+1] 组成的相邻元素对都存在于 adjacentPairs 中,存在形式可能是 [nums[i], nums[i+1]] ,也可能是 [nums[i+1], nums[i]] 。这些相邻元素对可以 按任意顺序 出现。
13+
题目数据保证所有由元素 `nums[i]``nums[i+1]` 组成的相邻元素对都存在于 `adjacentPairs` 中,存在形式可能是 `[nums[i], nums[i+1]]` ,也可能是 `[nums[i+1], nums[i]]` 。这些相邻元素对可以 按任意顺序 出现。
1414

15-
返回 原始数组 nums 。如果存在多种解答,返回 其中任意一个 即可。
15+
返回 原始数组 `nums` 。如果存在多种解答,返回 其中任意一个 即可。
1616

1717
示例 1:
1818
```
@@ -40,12 +40,12 @@ Tag : 「哈希表」、「双指针」、「模拟」
4040
```
4141

4242
提示:
43-
* nums.length == n
44-
* adjacentPairs.length == n - 1
45-
* adjacentPairs[i].length == 2
46-
* 2 <= n <= $10^5$
47-
* -$10^5$ <= nums[i], ui, vi <= $10^5$
48-
* 题目数据保证存在一些以 adjacentPairs 作为元素对的数组
43+
* $nums.length == n$
44+
* $adjacentPairs.length == n - 1$
45+
* $adjacentPairs[i].length == 2$
46+
* $2 <= n <= 10^5$
47+
* $-10^5 <= nums[i], u_i, v_i <= 10^5$
48+
* 题目数据保证存在一些以 `adjacentPairs` 作为元素对的数组
4949

5050
---
5151

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[1775. 通过最少操作次数使数组的和相等量]()** ,难度为 **中等**
4+
5+
Tag : 「枚举」、「贪心」、「数学」
6+
7+
8+
9+
给你两个长度可能不等的整数数组 `nums1` 和 `nums2` 。两个数组中的所有值都在 `1` 到 `6` 之间(包含 `1` 和 `6`)。
10+
11+
每次操作中,你可以选择 任意 数组中的任意一个整数,将它变成 `1` 到 `6` 之间 任意 的值(包含 `1` 和 `6`)。
12+
13+
请你返回使 `nums1` 中所有数的和与 `nums2` 中所有数的和相等的最少操作次数。如果无法使两个数组的和相等,请返回 `-1` 。
14+
15+
示例 1:
16+
```
17+
输入:nums1 = [1,2,3,4,5,6], nums2 = [1,1,2,2,2,2]
18+
19+
输出:3
20+
21+
解释:你可以通过 3 次操作使 nums1 中所有数的和与 nums2 中所有数的和相等。以下数组下标都从 0 开始。
22+
- 将 nums2[0] 变为 6 。 nums1 = [1,2,3,4,5,6], nums2 = [6,1,2,2,2,2] 。
23+
- 将 nums1[5] 变为 1 。 nums1 = [1,2,3,4,5,1], nums2 = [6,1,2,2,2,2] 。
24+
- 将 nums1[2] 变为 2 。 nums1 = [1,2,2,4,5,1], nums2 = [6,1,2,2,2,2] 。
25+
```
26+
示例 2:
27+
```
28+
输入:nums1 = [1,1,1,1,1,1,1], nums2 = [6]
29+
30+
输出:-1
31+
32+
解释:没有办法减少 nums1 的和或者增加 nums2 的和使二者相等。
33+
```
34+
示例 3:
35+
```
36+
输入:nums1 = [6,6], nums2 = [1]
37+
38+
输出:3
39+
40+
解释:你可以通过 3 次操作使 nums1 中所有数的和与 nums2 中所有数的和相等。以下数组下标都从 0 开始。
41+
- 将 nums1[0] 变为 2 。 nums1 = [2,6], nums2 = [1] 。
42+
- 将 nums1[1] 变为 2 。 nums1 = [2,2], nums2 = [1] 。
43+
- 将 nums2[0] 变为 4 。 nums1 = [2,2], nums2 = [4] 。
44+
```
45+
46+
提示:
47+
* $1 <= nums1.length, nums2.length <= 10^5$
48+
* $1 <= nums1[i], nums2[i] <= 6$
49+
50+
---
51+
52+
### 枚举 + 贪心 + 数学
53+
54+
`nums1` 的长度为 `n``nums2` 的长度为 `m`,根据题意两数组的值域分别为 $[n, 6n]$ 和 $[m, 6m]$,可分别视为数轴上的两条线段。
55+
56+
为了方便,我们人为固定 $n\leq m$,若不满足则交换两数组,返回 `minOperations(nums2, nums1)` 即可。
57+
58+
先来考虑无解的情况:当 $6n < m$ 时,说明两线段不重合,必然无法通过变换使得总和相等,直接返回 `-1`
59+
60+
由于 $\max(n, m)$ 的范围为 $1e5$,且 $nums[i]$ 的值域大小 $C = 6$,因此我们可以通过枚举最终目标和 `x`(两线段的重合部分)来做,枚举范围不超过 $6 \times 1e5$。
61+
62+
于是问题转换为:**对于一个原总和为 `sum` 的数组 `nums` 而言,按照题目的变换规则,至少经过多少次变换,才能将其总和变为 `x`**
63+
64+
根据原总和 `sum` 和目标结果 `x` 的大小关系进行分情况讨论(将两者差值绝对值记为 `d`):
65+
66+
* 当 $sum < x$ 时,对于原数为 $nums[i]$ 的数而言,其能变为不超过 $nums[i] - 1$ 的任意数。
67+
68+
例如 $6$ 能够变化为 $[1, 5]$ 中的任意数,即单个数值 $6$ 最多能够抵消 $6 - 1$ 个差值,不失一般性的可概括为原数为 $nums[i]$ 所能抵消的差值为 $nums[i] - 1$。
69+
70+
因此,我们贪心的使用较大数进行变换(从 $6$ 往 $2$ 枚举 `i`),对于每个数值 `i` 而言,其所能提供的个数为 $\min(\left \lceil \frac{d}{i - 1} \right \rceil, cnst[i])$。
71+
72+
* 当 $sum > x$ 时,同理,原数为 $nums[i]$ 所能提供的最大抵消数为 $6 - nums[i]$,因此我们贪心使用较小数进行变换(从 $1$ 往 $5$ 枚举 `i`),对于每个数值 `i` 而言,其所能提供的个数为 $\min(\left \lceil \frac{d}{6 - i} \right \rceil, cnst[i])$。
73+
74+
如此一来,我们通过枚举两线段重合点 `x`,复杂度为 $O(C \times \max(n, m))$,并通过复杂度为 $O(C)$ 的数学方法来得知将两原数组总和变为 `x` 所需要的操作次数 `cnt`,在所有的 `cnt` 取最小值即是答案。整体计算量为 $3.6 \times 10^6$,可以过。
75+
76+
77+
Java 代码:
78+
```Java
79+
class Solution {
80+
int[] c1 = new int[10], c2 = new int[10];
81+
int s1, s2;
82+
public int minOperations(int[] nums1, int[] nums2) {
83+
int n = nums1.length, m = nums2.length;
84+
if (n > m) return minOperations(nums2, nums1);
85+
if (m > 6 * n) return -1;
86+
for (int x : nums1) {
87+
c1[x]++; s1 += x;
88+
}
89+
for (int x : nums2) {
90+
c2[x]++; s2 += x;
91+
}
92+
int ans = n + m;
93+
for (int i = m; i <= 6 * n; i++) ans = Math.min(ans, getCnt(c1, s1, i) + getCnt(c2, s2, i));
94+
return ans;
95+
}
96+
int getCnt(int[] cnts, int sum, int x) {
97+
int ans = 0;
98+
if (sum > x) {
99+
for (int i = 6, d = sum - x; i >= 2 && d > 0; i--) {
100+
int c = Math.min((int) Math.ceil(d * 1.0 / (i - 1)), cnts[i]);
101+
ans += c; d -= c * (i - 1);
102+
}
103+
} else if (sum < x) {
104+
for (int i = 1, d = x - sum; i <= 5 && d > 0; i++) {
105+
int c = Math.min((int) Math.ceil(d * 1.0 / (6 - i)), cnts[i]);
106+
ans += c; d -= c * (6 - i);
107+
}
108+
}
109+
return ans;
110+
}
111+
}
112+
```
113+
Python 代码:
114+
```Python
115+
class Solution:
116+
def minOperations(self, nums1: List[int], nums2: List[int]) -> int:
117+
n, m = len(nums1), len(nums2)
118+
if n > m:
119+
return self.minOperations(nums2, nums1)
120+
if m > 6 * n:
121+
return -1
122+
c1, c2 = Counter(nums1), Counter(nums2)
123+
s1, s2 = sum(nums1), sum(nums2)
124+
def getCnt(cnts, tot, x):
125+
ans = 0
126+
if tot > x:
127+
d = tot - x
128+
for i in range(6, 1, -1):
129+
if d <= 0:
130+
break
131+
c = min(math.ceil(d / (i - 1)), cnts[i])
132+
ans, d = ans + c, d - c * (i - 1)
133+
elif tot < x:
134+
d = x - tot
135+
for i in range(1, 6):
136+
if d <= 0:
137+
break
138+
c = min(math.ceil(d / (6 - i)), cnts[i])
139+
ans, d = ans + c, d - c * (6 - i)
140+
return ans
141+
ans = n + m
142+
for i in range(m, 6 * n + 1):
143+
ans = min(ans, getCnt(c1, s1, i) + getCnt(c2, s2, i))
144+
return ans
145+
```
146+
* 时间复杂度:$O(C \times \max(n, m) \times C)$,其中 $C = 6$ 为 $nums[i]$ 的值域大小
147+
* 空间复杂度:$O(C)$
148+
149+
---
150+
151+
### 最后
152+
153+
这是我们「刷穿 LeetCode」系列文章的第 `No.1775` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
154+
155+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
156+
157+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
158+
159+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
160+

LeetCode/411-420/413. 等差数列划分(中等).md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ Tag : 「双指针」、「模拟」、「数学」
3131
```
3232

3333
提示:
34-
* 1 <= nums.length <= 5000
35-
* -1000 <= nums[i] <= 1000
34+
* $1 <= nums.length <= 5000$
35+
* $-1000 <= nums[i] <= 1000$
3636

3737
---
3838

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[93. 复原 IP 地址](https://mp.weixin.qq.com/s?__biz=MzU4NDE3MTEyMA==&tempkey=MTE5NF9PUlVickRVMVkveWdqQzNhSlJZeEVobW8yaXF3ZzV4U2NEMWpaQlI5MHN1cklxNFhNc3dCQlg0QnNpcXV1NGNqSG04X2dMTi1TN0RlUmpEd2YxaHJyLU00MTkxNEhtRi1kTmFoUnpicXFocW9oYnItU3BLU3RPS1pvODEtRXg2VkpyVWNCbFhaUmNKbnhnN21VN1JndzZwRG1WYlUwdGNYTW5KMTlBfn4%3D)** ,难度为 **中等**
4+
5+
Tag : 「回溯」、「DFS」
6+
7+
8+
9+
有效 `IP` 地址 正好由四个整数(每个整数位于 `0``255` 之间组成,且不能含有前导 `0`),整数之间用 `'.'` 分隔。
10+
11+
例如:`"0.1.2.201"``"192.168.1.1"` 是 有效 `IP` 地址,但是 `"0.011.255.245"``"192.168.1.312"``"[email protected]"` 是 无效 `IP` 地址。
12+
13+
给定一个只包含数字的字符串 `s` ,用以表示一个 `IP` 地址,返回所有可能的有效 `IP` 地址,这些地址可以通过在 `s` 中插入 `'.'` 来形成。你 不能 重新排序或删除 `s` 中的任何数字。你可以按 任何 顺序返回答案。
14+
15+
示例 1:
16+
```
17+
输入:s = "25525511135"
18+
19+
输出:["255.255.11.135","255.255.111.35"]
20+
```
21+
示例 2:
22+
```
23+
输入:s = "0000"
24+
25+
输出:["0.0.0.0"]
26+
```
27+
示例 3:
28+
```
29+
输入:s = "101023"
30+
31+
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
32+
```
33+
34+
提示:
35+
* $1 <= s.length <= 20$
36+
* `s` 仅由数字组成
37+
38+
---
39+
40+
### 回溯算法
41+
42+
[131. 分割回文串](https://mp.weixin.qq.com/s?__biz=MzU4NDE3MTEyMA==&mid=2247487047&idx=1&sn=117c48f20778868442fce44e100d2ea8) 一样,同样是一道求所有方案的题目,只能是没有太多优化的「爆搜」做法。
43+
44+
设计递归函数为 `void dfs(int idx, int n, List<Integer> cur)`,其中 `idx``n` 分别代表当前处理字符串 `s` 的哪个位置,以及字符串 `s` 的总长度,而 `cur` 的则是代表子串 $s[0 ... (idx - 1)]$ 部分的具体划分方案。
45+
46+
用题目样例 `s = "25525511135"` 作为 🌰,`n` 固定为 `11`,当 `idx = 3` 时,`cur` 为 $s[0...2] = 255$ 部分的划分方案,`cur` 可能是 `[2,5,5]``[2,55]``[25,5]``[255]` 之一,在 `cur` 的基础上,我们继续爆搜剩余部分,即递归执行 `dfs(idx, n, cur)`,算法会将剩余部分的划分方案添加到 `cur` 上,我们只需要确保每次追加到 `cur` 的数值符合要求即可(没有前导零 且 范围在 $[0, 255]$ 中)。
47+
48+
在单次回溯过程中,我们可以将 `idx` 作为当前划分数字的左端点,通过枚举的形式找到右端点 `j`,并将当前数字 $s[idx ... (j - 1)]$ 加到 `cur` 中(若合法),回溯到底后再添加到 `cur` 的元素进行移除。
49+
50+
`idx = n` 代表整个 `s` 已经处理完成,若此时 `cur` 恰好有 $4$ 个元素,说明我们找到了一组合法方案,将其拼接成字符串追加到答案数组中。同时也是由于划分过程中 `cur` 最多只有 $4$ 个元素,我们可以用此做简单剪枝。
51+
52+
Java 代码:
53+
```Java
54+
class Solution {
55+
List<String> ans = new ArrayList<>();
56+
char[] cs;
57+
public List<String> restoreIpAddresses(String s) {
58+
cs = s.toCharArray();
59+
dfs(0, cs.length, new ArrayList<>());
60+
return ans;
61+
}
62+
void dfs(int idx, int n, List<Integer> cur) {
63+
if (cur.size() > 4) return ;
64+
if (idx == n) {
65+
if (cur.size() == 4) {
66+
StringBuilder sb = new StringBuilder();
67+
for (int i = 0; i < 4; i++) sb.append(cur.get(i)).append(".");
68+
ans.add(sb.substring(0, sb.length() - 1));
69+
}
70+
} else {
71+
for (int i = idx; i < n; i++) {
72+
int t = 0;
73+
for (int j = idx; j <= i; j++) t = t * 10 + (cs[j] - '0');
74+
if (cs[idx] == '0' && i != idx) break;
75+
if (t > 255) break;
76+
cur.add(t);
77+
dfs(i + 1, n, cur);
78+
cur.remove(cur.size() - 1);
79+
}
80+
}
81+
}
82+
}
83+
```
84+
Python 代码:
85+
```Python
86+
class Solution:
87+
def restoreIpAddresses(self, s: str) -> List[str]:
88+
ans = []
89+
def dfs(idx, n, cur):
90+
if len(cur) > 4:
91+
return
92+
if idx == n:
93+
if len(cur) == 4:
94+
ans.append('.'.join(cur))
95+
else:
96+
for i in range(idx, n):
97+
t = 0
98+
for j in range(idx, i + 1):
99+
t = t * 10 + (ord(s[j]) - ord('0'))
100+
if s[idx] == '0' and i != idx:
101+
break
102+
if t > 255:
103+
break
104+
cur.append(str(t))
105+
dfs(i + 1, n, cur)
106+
cur.pop()
107+
dfs(0, len(s), [])
108+
return ans
109+
```
110+
TypeScript 代码:
111+
```TypeScript
112+
function restoreIpAddresses(s: string): string[] {
113+
const ans = new Array<string>()
114+
function dfs(idx: number, n: number, cur: Array<number>): void {
115+
if (cur.length > 4) return
116+
if (idx == n) {
117+
if (cur.length == 4) {
118+
let str = ''
119+
for (let i = 0; i < 4; i++) str += cur[i] + "."
120+
ans.push(str.substring(0, str.length - 1))
121+
}
122+
} else {
123+
for (let i = idx; i < n; i++) {
124+
let t = 0
125+
for (let j = idx; j <= i; j++) t = t * 10 + (s.charCodeAt(j) - '0'.charCodeAt(0))
126+
if (s[idx] == '0' && i != idx) break
127+
if (t > 255) break
128+
cur.push(t)
129+
dfs(i + 1, n, cur)
130+
cur.pop()
131+
}
132+
}
133+
}
134+
dfs(0, s.length, new Array<number>())
135+
return ans
136+
}
137+
```
138+
* 时间复杂度:爆搜不讨论时空复杂度
139+
* 空间复杂度:爆搜不讨论时空复杂度
140+
141+
---
142+
143+
### 最后
144+
145+
这是我们「刷穿 LeetCode」系列文章的第 `No.93` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
146+
147+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
148+
149+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
150+
151+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
152+

0 commit comments

Comments
 (0)