Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9103631

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

File tree

6 files changed

+445
-12
lines changed

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+
先来考虑无解的情况:当 6ドルn < m$ 时,说明两线段不重合,必然无法通过变换使得总和相等,直接返回 `-1`
59+
60+
由于 $\max(n, m)$ 的范围为 1ドルe5,ドル且 $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"``"192.168@1.1"` 是 无效 `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)

AltStyle によって変換されたページ (->オリジナル) /