Skip to content

Commit 2f83ccf

Browse files
committed
五刷46
1 parent be32926 commit 2f83ccf

File tree

5 files changed

+99
-9
lines changed

5 files changed

+99
-9
lines changed

Diff for: docs/0000-21-decrease-and-conquer.adoc

+3
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ D瓜哥最早知道减治法是在 https://book.douban.com/subject/26337727/[《
1414
* **减去的规模是可变的。**在减治法的减可变规模(variable-size-decrease)变化形式中,算法在每次迭代时,规模减小的模式都是不同的。
1515
** 计算最大公约数的欧几里得算法是这种情况的一个很好的例子。 stem:[gcd(m, n)=gcd(n,m mod n)]
1616
17+
== 参考资料
18+
19+
. https://cloud.tencent.com/developer/article/1532598[【算法学习】减治 · 分治 · 变治^]

Diff for: docs/0000-25-subsets.adoc

+42-8
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,52 @@
11
[#0000-25-subsets]
22
= Subsets 子集
33

4-
一般都是使用多重DFS
4+
超级多的编程面试问题都会涉及到排列和组合问题。一般都是使用回溯来解决该类问题,回溯法属于 DFS 解法。子集问题模式讲的是用 BFS 来处理这些问题。
55

6-
超级多的编程面试问题都会涉及到排列和组合问题。子集问题模式讲的是用BFS来处理这些问题。
76

8-
这个模式是这样的:
7+
== 子集
98

10-
给一组数字 [1, 5, 3]
9+
举例来说明一下这个模式:
10+
11+
给一组数字 `[1, 5, 3]`
12+
13+
. 我们从空集开始:`[[]]`
14+
. 把第一个数 `1`,加到之前已经存在的集合中:`[[], [1]]`;
15+
. 把第二个数 `5`,加到之前的集合中得到:`[[], [1], [5], [1,5]]`;
16+
. 再加第三个数 `3`,则有:`[[], [1], [5], [1,5], [3], [1,3], [5,3], [1,5,3]]`.
17+
18+
如果原有集合中存在重复元素,那么就需要针对这种情况特殊处理一下。流程如下:
19+
20+
给一组数字 `[5, 1, 5]`
21+
22+
. 先对原有集合进行排序: `[1, 5, 3]`
23+
. 从空集开始:`[[]]`
24+
. 把第一个数 `1`,加到之前已经存在的集合中:`[[], [1]]`;
25+
. 把第二个数 `5`,加到之前的集合中得到:`[[], [1], [5], [1,5]]`;
26+
. 处理第三个数,也是 `5` 时需要注意:
27+
.. 如果还是按照上述方案处理,那么就会得到如下结果: `[[], [1], [5], [1,5], *[5], [1, 5]*, [5, 5], [1,5, 5]]`。这里出现了重复子集: `[5], [1, 5]`。该方案不通过,❌
28+
.. 观察最后生成的所有子集与重复的子集,会发现重复的子集,在处理第二个数时,已经处理过 `[], [1]`,如果再次处理 `5`,那么就会出现重复。所以,只需要处理在处理上一个相同的数时新增加的子集即可。上一个相同数新增的子集是 `[5], [1,5]`,只需要在这些子集后面增加当前数字即可。这样最后的子集就是:`[[], [1], [5], [1,5], [5, 5], [1,5, 5]]`。方案通过 ✅
29+
30+
== 排列
31+
32+
举例来说明一下这个模式在处理排列问题时的步骤:
33+
34+
给一组数字 `[1, 5, 3]`
35+
36+
. 把第一个数 `1`,集合中:`[[1]]`;
37+
. 把第二个数 `5`,加到之前的集合中得到,由于 `[1, 5]` 和 `[5, 1]` 属于两个排列,那么就需要在所有可能的位置都增加一下,最后得到的排列如下::`[[5, 1], [1,5]]`;
38+
. 再加第三个数 `3`,也是如上,在所有可能的位置都增加,最终排列如下:`[[3, 5, 1], [5, 3, 1],[5, 1, 3], [3, 1, 5], [1, 3, 5], [1, 5, 3]]`。
39+
40+
思考一下:如何处理有重复元素的排列?
41+
42+
// [1, 5, 5]
43+
//
44+
// `[[1]]`
45+
//
46+
// `[[5, 1], [1,5]]`
47+
//
48+
// `[[5, 5, 1], *[5, 5, 1]*,[5, 1, 5], *[5, 1, 5]*, [1, 5, 5], *[1, 5, 5]*]`
1149

12-
. 我们从空集开始:[[]]
13-
. 把第一个数(1),加到之前已经存在的集合中:[[], [1]];
14-
. 把第二个数(5),加到之前的集合中得到:[[], [1], [5], [1,5]];
15-
. 再加第三个数(3),则有:[[], [1], [5], [1,5], [3], [1,3], [5,3], [1,5,3]].
1650

1751
如果判断这种子集模式:
1852

Diff for: docs/0046-permutations.adoc

+10-1
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,23 @@ include::{sourcedir}/_0046_Permutations_3.java[tag=answer]
6666
----
6767
--
6868
69-
四刷::
69+
四刷(回溯)::
7070
+
7171
--
7272
[{java_src_attr}]
7373
----
7474
include::{sourcedir}/_0046_Permutations_4.java[tag=answer]
7575
----
7676
--
77+
78+
五刷(子集)::
79+
+
80+
--
81+
[{java_src_attr}]
82+
----
83+
include::{sourcedir}/_0046_Permutations_5.java[tag=answer]
84+
----
85+
--
7786
====
7887

7988
== 参考资料

Diff for: logbook/202503.adoc

+5
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,11 @@ endif::[]
210210
|{doc_base_url}/0090-subsets-ii.adoc[题解]
211211
|⭕️ 子集,需要注意重复元素的处理。现在用 `Set` 记录已添加子集的方案还可以再优化。添加优化解法。
212212

213+
|{counter:codes2503}
214+
|{leetcode_base_url}/permutations/[46. 全排列^]
215+
|{doc_base_url}/0046-permutations.adoc[题解]
216+
|✅ 子集。注意对比子集模式在处理子集和排列时的不同:①子集直接在结果中添加新子集;②排列则是将结果中的元素出队,添加新元素后,再入队。
217+
213218
|===
214219

215220
截止目前,本轮练习一共完成 {codes2503} 道题。
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.diguage.algo.leetcode;
2+
3+
import java.util.ArrayList;
4+
import java.util.LinkedList;
5+
import java.util.List;
6+
import java.util.Queue;
7+
8+
public class _0046_Permutations_5 {
9+
// tag::answer[]
10+
/**
11+
* @author D瓜哥 · https://www.diguage.com
12+
* @since 2025-04-10 17:22:39
13+
*/
14+
public List<List<Integer>> permute(int[] nums) {
15+
Queue<List<Integer>> result = new LinkedList<>();
16+
result.offer(new ArrayList<>(List.of(nums[0])));
17+
for (int i = 1; i < nums.length; i++) {
18+
int num = nums[i];
19+
int size = result.size();
20+
for (int j = 0; j < size; j++) {
21+
List<Integer> tmp = result.poll();
22+
for (int k = 0; k <= tmp.size(); k++) {
23+
List<Integer> adding = new ArrayList<>(tmp);
24+
if (k == tmp.size()) {
25+
adding.add(num);
26+
} else {
27+
adding.add(k, num);
28+
}
29+
result.offer(adding);
30+
}
31+
}
32+
}
33+
return new ArrayList<>(result);
34+
}
35+
// end::answer[]
36+
public static void main(String[] args) {
37+
new _0046_Permutations_5().permute(new int[]{1, 2, 3});
38+
}
39+
}

0 commit comments

Comments
 (0)