leetcode77.Combinations

题目要求

1
2
3
4
5
6
7
8
9
10
11
12
13
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

For example,
If n = 4 and k = 2, a solution is:

[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

有整数从1到n,问从中任选两个数有多少排列组合的结果(顺序无关)

思路一:利用链表(超时问题)

这题其实是动态编码的一个题目,可以通过链表实现队列存储前一种情况。再在前一种情况下继续下一轮的遍历,并将结果添加到队列末尾。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> result = new LinkedList<List<Integer>>();
if(k==0){
return result;
}
for(int i = 0 ; i+k<=n ; i++){
result.add(Arrays.asList(i+1));
}
while(result.get(0).size() != k){
List<Integer> currentList = result.remove(0);
for(int i = currentList.get(currentList.size()-1) + 1 ; i<=n ; i++){
List<Integer> temp = new ArrayList<Integer>(currentList);
temp.add(i);
result.add(temp);
}
}
return result;
}

但是在这里存在超时问题,归根结底在于每一次都要创建新的数组用来保存临时结果,既占用内存又影响效率。

思路二:递归

其实,通过递归的方法我们也可以在前一轮的基础上进行下一轮的计算。递归代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 public List<List<Integer>> combine2(int n, int k){
List<List<Integer>> result = new ArrayList<List<Integer>>();
if(k==0) return result;
combine2(result, new ArrayList<Integer>(), 1, n, k);
return result;
}

public void combine2(List<List<Integer>> currentResult, List<Integer> list, int start, int n, int k){
if(k==0){
currentResult.add(new ArrayList<Integer>(list));
return;
}
while(start+k-1<=n){
list.add(start++);
combine2(currentResult, list, start, n, k-1);
list.remove(list.size()-1);
}
}