给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
示例 2:输入:n = 1, k = 1
输出:[[1]]
提示:
1 <= n <= 20
1 <= k <= n来源:力扣(LeetCode)
链接:力扣
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
可用回溯法解决:可以先看看博文LeetCode46 全排列,代码更加简单,作为回溯法熟悉和了解;
版本一(答案错误):输出有重复
public class Solution {
public IList<IList<int>> Combine(int n, int k)
{
return HleetCode.N77Combinations.Commit(n,k);
}
public partial class HleetCode
{
//77组合题解
public static class N77Combinations
{
private static List<IList<int>> _res=null;
public static IList<IList<int>> Commit(int n, int k)
{
//异常提前返回
if(n<0||k<0) return null;
if(k>n) return null;
//创建结果对象
_res=new List<IList<int>>();
int[] srcNums=new int[n];
for(int i=0;i<n;i++)
{
srcNums[i]=i+1;
}
//执行算法
Dfs(srcNums,new bool [srcNums.Length],new Stack<int>(),k);
//返回结果
return _res;
}
//回溯算法实现
private static void Dfs(int[] srcNums,bool [] isUsed,Stack<int> path,int k)
{
//递归终结条件
if(path.Count==k)
{
_res.Add(new List<int>(path));
return;
}
//递归与回溯
for(int i=0;i<srcNums.Length;i++)
{
if(isUsed[i]) continue;
path.Push(srcNums[i]);
isUsed[i]=true;
Dfs(srcNums,isUsed,path,k);
isUsed[i]=false;
path.Pop();
}
}
}
}
}
版本二(成功):添加startIndex,去除重复
//回溯算法实现,需添加每一层搜索起点startIndex,避免之前的组合换个顺序再加入一遍
private static void Dfs(int[] srcNums,bool [] isUsed,Stack<int> path,int k,int startIndex)
{
//递归终结条件
if(path.Count==k)
{
_res.Add(new List<int>(path));
return;
}
//递归与回溯
for(int i=startIndex;i<srcNums.Length;i++)
{
if(isUsed[i]) continue;
path.Push(srcNums[i]);
isUsed[i]=true;
Dfs(srcNums,isUsed,path,k,i);
isUsed[i]=false;
path.Pop();
}
}
版本三:优化
Dfs(srcNums,isUsed,path,k,i+1);//去掉重复搜索
完整实现:
public class Solution {
public IList<IList<int>> Combine(int n, int k)
{
return HleetCode.N77Combinations.Commit(n,k);
}
public partial class HleetCode
{
//77组合题解
public static class N77Combinations
{
private static List<IList<int>> _res=null;
public static IList<IList<int>> Commit(int n, int k)
{
//异常提前返回
if(n<0||k<0) return null;
if(k>n) return null;
//创建结果对象
_res=new List<IList<int>>();
int[] srcNums=new int[n];
for(int i=0;i<n;i++)
{
srcNums[i]=i+1;
}
//执行算法
Dfs(srcNums,new bool [srcNums.Length],new Stack<int>(),k,0);
//返回结果
return _res;
}
//回溯算法实现,需添加每一层搜索起点startIndex,避免之前的组合换个顺序再加入一遍
private static void Dfs(int[] srcNums,bool [] isUsed,Stack<int> path,int k,int startIndex)
{
//递归终结条件
if(path.Count==k)
{
_res.Add(new List<int>(path));
return;
}
//递归与回溯
for(int i=startIndex;i<srcNums.Length;i++)
{
if(isUsed[i]) continue;
path.Push(srcNums[i]);
isUsed[i]=true;
Dfs(srcNums,isUsed,path,k,i+1);
isUsed[i]=false;
path.Pop();
}
}
}
}
}
算法性能: