当前位置:网站首页>回溯——77. 组合
回溯——77. 组合
2022-07-25 23:55:00 【向着百万年薪努力的小赵】
1 题目描述
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/combinations
2 题目示例
示例 1:
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
示例 2:
输入:n = 1, k = 1
输出:[[1]]
3 题目提示
1 <= n <= 20
1 <= k <= n
4 思路
重点概括:
- 如果解决—个问题有多个步骤,每一个步骤有多种方法,题目又要我们找出所有的方法,可以使用回溯算法;
- 回溯算法是在—棵树上的深度优先遍历(因为要找所有的解,所以需要遍历);
- 组合问题,相对于排列问题而言,不计较一个组合内元素的顺序性(即[1,2,3]与[1,3,2]认为是同一个组合),因此很多时候需要按某种顺序展开搜索,这样才能做到不重不漏。
既然是树形问题上的深度优先遍历,因此首先画出树形结构。例如输入:n = 4,k = 2,我们可以发现如下递归结构:
- 如果组合里有1,那么需要在[2,3,4]里再找1个数;
- 如果组合里有2,那么需要在[3,4]里再找1数。注意:这里不能再考虑1,因为包含1的组合,在第1种情况中已经包含。
依次类推(后面部分省略),以上描述体现的递归结构是:在以n结尾的候选数组里,选出若干个元素。
说明:
- 叶子结点的信息体现在从根结点到叶子结点的路径上,因此需要一个表示路径的变量path,它是一个列表,特别地,path是一个栈;
- 每一个结点递归地在做同样的事情,区别在于搜索起点,因此需要一个变量start ,表示在区间Lbegin, n]里选出若干个数的组合;
- 可能有一些分支没有必要执行,我们放在优化中介绍。
5 我的答案
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
public class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
if (k <= 0 || n < k) {
return res;
}
// 从 1 开始是题目的设定
Deque<Integer> path = new ArrayDeque<>();
dfs(n, k, 1, path, res);
return res;
}
private void dfs(int n, int k, int begin, Deque<Integer> path, List<List<Integer>> res) {
// 递归终止条件是:path 的长度等于 k
if (path.size() == k) {
res.add(new ArrayList<>(path));
return;
}
// 遍历可能的搜索起点
for (int i = begin; i <= n; i++) {
// 向路径变量里添加一个数
path.addLast(i);
// 下一轮搜索,设置的搜索起点要加 1,因为组合数理不允许出现重复的元素
dfs(n, k, i + 1, path, res);
// 重点理解这里:深度优先遍历有回头的过程,因此递归之前做了什么,递归之后需要做相同操作的逆向操作
path.removeLast();
}
}
}
优化
我们上面的代码,搜索起点遍历到 n,即:递归函数中有下面的代码片段:
// 从当前搜索起点 begin 遍历到 n
for (int i = begin; i <= n; i++) {
path.addLast(i);
dfs(n, k, i + 1, path, res);
path.removeLast();
}
事实上,如果n = 7,k = 4,从5开始搜索就已经没有意义了,这是因为:即使把5选上,后面的数只有6和7,一共就3个候选数,凑不出4个数的组合。因此,搜索起点有上界,这个上界是多少,可以举几个例子分析。
分析搜索起点的上界,其实是在深度优先遍历的过程中剪枝,剪枝可以避免不必要的遍历,剪枝剪得好,可以大幅度节约算法的执行时间。
容易知道:搜索起点和当前还需要选几个数有关,而当前还需要选几个数与已经选了几个数有关,即与path的长度相关。我们举几个例子分析:
例如: n = 6 , k = 4。
path.size() == 1的时候,接下来要选择3个数,搜索起点最大是4,最后一个被选的组合是[4,5,6];
path.size() == 2的时候,接下来要选择2个数,搜索起点最大是5,最后一个被选的组合是[5, 6];
path.size() == 3的时候,接下来要选择1个数,搜索起点最大是6,最后一个被选的组合是[6] ;
再如:n = 15 , k = 4。
path.size() == 1的时候,接下来要选择3个数,搜索起点最大是13,最后一个被选的是[13,14,15] ;
path.size() == 2的时候,接下来要选择2个数,搜索起点最大是14,最后一个被选的是[14, 15];
path.size() == 3的时候,接下来要选择1个数,搜索起点最大是15,最后一个被选的是[15] ;
可以归纳出:
搜索起点的上界+接下来要选择的元素个数一1 = n
其中,接下来要选择的元素个数= k - path.size(),整理得到:
搜索起点的上界 = n - (k - path.size()) + 1
所以,我们的剪枝过程就是:把i <= n改成i <= n - (k -path. size() +1 :
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
public class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
if (k <= 0 || n < k) {
return res;
}
Deque<Integer> path = new ArrayDeque<>();
dfs(n, k, 1, path, res);
return res;
}
private void dfs(int n, int k, int index, Deque<Integer> path, List<List<Integer>> res) {
if (path.size() == k) {
res.add(new ArrayList<>(path));
return;
}
// 只有这里 i <= n - (k - path.size()) + 1 与参考代码 1 不同
for (int i = index; i <= n - (k - path.size()) + 1; i++) {
path.addLast(i);
dfs(n, k, i + 1, path, res);
path.removeLast();
}
}
}
边栏推荐
- Interview focus - TCP protocol of transport layer
- [ManageEngine] servicedesk plus won the 2022 safety model engineering data safety award
- 静态代理+动态代理
- Redis extended data type (jump table /bitmaps/hyperloglog/geospatial)
- [Muduo] EventLoop event cycle
- TOPSIS and entropy weight method
- Zhiniu stock -- 09
- 浅识 OWASP
- Matchmaker's words
- [day.2] Joseph Ring problem, how to use arrays to replace circular linked lists (detailed explanation)
猜你喜欢

Payment terms in SAP message No. vg202 IDoc e1edk18 have been transferred: check data

【JUC】并发需要了解的关键字volatile

结对编程实践心得

Call nailing API and report an error: the signature sent by the robot is expired; Solution: please keep the signature generation time and sending time within timestampms
![[Database Foundation] summary of MySQL Foundation](/img/89/e22c232b0183eaae35a9f45a40ff36.jpg)
[Database Foundation] summary of MySQL Foundation

How does JS judge whether the current date is within a certain range

MySQL的DDL、DML和DQL的基本语法

Qpprogressbar for QT style (QSS) application

SIGIR‘22 推荐系统论文之图网络篇

ArcGIS cuts TIF images (grid data) according to the vector range, merges shp files in batches, cuts vectors in the region according to the vector range, outputs the geographic coordinate system, conve
随机推荐
寻找链表的中间节点
Demo of pointer function
行为型模式之迭代器模式
Exercise (2) create a set to store the elements "1", "$", "2", "$", "3", "$", "4"“
Using jetpack libraries in applications
Lua script Wireshark plug-in to resolve third-party private protocols
Swap, move, forward, exchange of utility component learning
老旧笔记本电脑变服务器(笔记本电脑+内网穿透)
Fixed and alternate sequential execution of modes
Leetcode 0135. distribute candy
热部署和热加载有什么区别?
Bubble sort idea and Implementation
The process of finding free screen recording software - I didn't expect win10 to come with this function
红娘的话
Exercise (1) create a set C1 to store the elements "one", "two", "three"“
[testing technology automated testing pytest] basic summary of pytest
Call nailing API and report an error: the signature sent by the robot is expired; Solution: please keep the signature generation time and sending time within timestampms
智牛股--09
Get the data of Mafeng Hotel
【JUC】并发需要了解的关键字volatile