Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
Example:
Input: n = 4, k = 2
Output:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
是一种穷举遍历的思想;
自己的代码:(递归 DFS)
Runtime: 39 ms, faster than 37.50% of Java online submissions for Combinations.
Memory Usage: 43.8 MB, less than 26.50% of Java online submissions for Combinations.
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
class Solution {
public static List<List<Integer>> combine(int n, int k) {
List<List<Integer>> results = new ArrayList<>();
List<Integer> tempList = new ArrayList<>();
helper(results,tempList,1,n,k);
return results;
}
public static void helper(List<List<Integer>> results ,List<Integer> tempList,int start,int n, int k) {
if(k == 0) {
List<Integer> list = new ArrayList<>();
for(Integer i : tempList) {
list.add(i);
}
results.add(list);
return;
}
for(int i=start;i<=n;i++) {
tempList.add(i);// not add(start)
helper(results,tempList,i+1,n,k-1); // 参数三:是i+1,不是start+1
tempList.remove(new Integer(i));
}
}
public static void main(String[] args) {
int n = 4;
int k = 2;
List<List<Integer>> list = combine(n,k);
System.out.println(list);
}
}
递归思想:(分解成子问题)
0)因为不确定k的大小,所以想到用递归
1)helper(start,n,k)的功能就是获得从start到n的数,组成的长度为k的所有可能结果
2)那么helper(start+1,n,k-1)的功能就是获得从start+1到n的数,组成的长度为k-1的所有可能结果
自己的代码2
import java.util.ArrayList;
import java.util.List;
public class WelcomeApp {
private static int count = 0;
private static StringBuilder sb = new StringBuilder();
private static List<String> lists = new ArrayList<>();
// 获得n选k的全部组合
public static void getK(int n, int k, int index,int start) {
if(index > 3) {
lists.add(sb.toString());
count++;
return;
}
for(int i=start;i<=n-k+1;i++) {
String temp = i+" ";
sb.append(temp);
getK(n, k-1, index+1,i+1); // 注意第2 3 4个参数的设置;
sb.delete(sb.length()-temp.length(), sb.length()); // 这句回溯一定不能少
}
}
public static void main(String[] args) {
int n=12;// 1,2,3,4,5
int k=3;//取出3个数
getK(n, k, 1,1);
for(String str : lists) {
System.out.println(str);
}
System.out.println("count = "+count);
}
}
小结:
a)应用DFS进行穷举遍历时,回溯的步骤是一定不能少的
别人的代码:
方法一:递归 + 回溯(和我的思路一模一样)
class Solution {
public static List<List<Integer>> combine(int n, int k) {
List<List<Integer>> combs = new ArrayList<List<Integer>>();
combine(combs, new ArrayList<Integer>(), 1, n, k);
return combs;
}
public static void combine(List<List<Integer>> combs, List<Integer> comb, int start, int n, int k) {
if(k==0) {
combs.add(new ArrayList<Integer>(comb)); // 直接通过构造函数,复制一个list
return;
}
for(int i=start;i<=n;i++) {
comb.add(i);
combine(combs, comb, i+1, n, k-1);
comb.remove(comb.size()-1); // 使用的是remove(index)这个方法
}
}
}
1)时间复杂度:The time complexity is "n times n choose k".
"n choose k" equals (n!/((n-k)! * k!)). In full notation is O(n * (n!/((n-k)! * k!))).
We will have "n choose k" combinations and in each call we will do O(n) work to copy the array to the answer.
和方法一相同的思路的Python解法:
class Solution(object):
def combine(self, n, k):
"""
:type n: int
:type k: int
:rtype: List[List[int]]
"""
res = []
def gen(i, tmp):
if len(tmp) == k:
res.append(list(tmp))
return
if i > n:
return
for j in range(i, n+1):
tmp.append(j)
gen(j+1, tmp)
tmp.pop()
gen(1, [])
return res
class Solution(object):
def combine(self, n, k):
"""
:type n: int
:type k: int
:rtype: List[List[int]]
"""
results = []
result = []
def DFS(results, result, start, n, k):
if(k==len(result)):
results.append(copy.deepcopy(result)) # python append()与深拷贝、浅拷贝应该注意,此处有一个大坑
return
for i in range(start,n+1,1):
result.append(i)
DFS(results, result, i+1, n, k)
result.pop()
DFS(results, result, 1, n, k)
return results
"""
[Python]_DFS_beats 97.24%
The key is to stop earlier (i.e. prune the search space) if the number of numbers could be selected (n-i) is less than the number of numbers we need to select (k).
当剩余的可以被选择的数的个数n-i,小于我们所需要选择的数的个数k,那么就提前终止,不用递归函数再进行下去
"""
class Solution:
def combine(self, n: 'int', k: 'int') -> 'List[List[int]]':
res = []
cur = []
self.combine_helper(n, k, 0, cur, res)
return res
def combine_helper(self, n, k, idx, cur, res):
if k == 0:
res.append(cur[:])
else:
for i in range(idx, n):
if k > (n-i):
break
val = i + 1
cur.append(val)
self.combine_helper(n, k-1, i+1, cur, res)
cur.pop()