78. Subsets

Given an integer array nums of unique elements, return all possible subsets (the power set).

The solution set must not contain duplicate subsets. Return the solution in any order.

回溯,先添加一个空集,然后回溯各个单独节点。
递归时传入数组内当前数字之后的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
ret.add(new ArrayList<>());

for(int i = 0; i < nums.length ; i++){
backtrack(ret, new ArrayList<>(), nums, i);
}
return ret;
}

private void backtrack(List<List<Integer>> ret, List<Integer> arr, int[] nums, int i){
if(i == nums.length-1){
arr.add(nums[i]);
ret.add(new ArrayList<>(arr));
return;
}

arr.add(nums[i]);
ret.add(new ArrayList<>(arr));
for(int j = i+1; j < nums.length; j++){
backtrack(ret, arr, nums, j);
arr.remove(arr.size()-1);
}
}
}

797. All Paths From Source to Target

Given a directed acyclic graph (DAG) of n nodes labeled from 0 to n - 1, find all possible paths from node 0 to node n - 1 and return them in any order.

The graph is given as follows: graph[i] is a list of all nodes you can visit from node i (i.e., there is a directed edge from node i to node graph[i][j]).

回溯。DFS搜索所有的路径。
当搜索到最后一个位置时,保存动态数组并返回。(此处需要深拷贝数组。)
回到上一层,取走动态数组的最后一个节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
List<List<Integer>> ret = new LinkedList<>();
dfs(ret, new ArrayList<>(), graph, 0);
return ret;
}

private void dfs(List<List<Integer>> ret, List<Integer> arr, int[][] graph, int i){
if( i == graph.length - 1){
arr.add(i);
ret.add(new ArrayList(arr));
return;
}
arr.add(i);
for( int j : graph[i] ){
dfs(ret, arr, graph, j);
arr.remove(arr.size()-1);
}
}
}

784. Letter Case Permutation

答案
Given a string s, you can transform every letter individually to be lowercase or uppercase to create another string.

Return a list of all possible strings we could create. Return the output in any order.

当前字符如果为数字,则直接添加并递归。(将字符隐式转换为整数判断是否为数字,可提升速度。)
当前字符如果为字母,则大小写分别添加到递归。(类似于回溯。)
当字符串长度与搜寻字符串相等时,添加到列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
List<String> ans;
String _s;
public List<String> letterCasePermutation(String s) {
ans = new ArrayList();
_s = s;

backTrack(new StringBuilder(),0);
return ans;

}

private void backTrack(StringBuilder sb, int i){
if(i == _s.length()){
ans.add(sb.toString());
return;
}
char curr = _s.charAt(i);
if ( isNums(curr) ){
sb.append(curr);
backTrack(sb, i+1);
}
else{
StringBuilder sb2 = new StringBuilder(sb);
sb.append(Character.toLowerCase(curr));
backTrack(sb, i+1);
sb2.append(Character.toUpperCase(curr));
backTrack(sb2, i+1);
}
}

private boolean isNums(char c){
if ( (int)c >= (int)'0' && (int)c <= (int)'9' ){
return true;
}
return false;
}
}

46. Permutations

问题
Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.

回溯,建立搜索树。
每次遍历nums中的元素。
如果未遍历过该元素,则向链表及set中添加。
向下递归,链表长度达到nums的长度时返回。
然后从set和链表中移除上一个值,回溯到上一个节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
List<List<Integer>> ans;
HashSet<Integer> set;
public List<List<Integer>> permute(int[] nums) {
ans = new ArrayList();
set = new HashSet();
backTrack(new LinkedList(), nums, nums.length, nums.length);
return ans;
}

private void backTrack(LinkedList<Integer> list,int[] nums, int n, int k){
if(k == 0){
ans.add(new ArrayList(list));
return;
}
for(int i = 0; i < n ; i++){
if(!set.contains(nums[i])){
list.add(nums[i]);
set.add(nums[i]);
backTrack(list, nums , n, k-1);
set.remove(nums[i]);
list.removeLast();
}
}
}
}

77. Combinations

问题
Given two integers n and k, return all possible combinations of k numbers out of the range [1, n].

You may return the answer in any order.

回溯,构建搜索树。
子节点取出的数值应大于父节点中取出的数值。
直到树高度达到k后返回。

返回时,要new一个List,将原有list传入。
否则添加到ans的值只是list的内存地址。
ArrayList换成LinkedList可以优化一些速度,因为可以直接removeLast。(22ms -> 16ms)
i的范围限制在start到n-k+1,后面的限制容易被忽略,可以大幅度减枝,优化速度。(16ms -> 1ms)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
List<List<Integer>> ans;
public List<List<Integer>> combine(int n, int k) {
ans = new ArrayList<>();
backTrack(new LinkedList(),1,n,k);
return ans;
}

private void backTrack(LinkedList<Integer> list, int start, int n, int k){
if (k == 0){
ans.add(new ArrayList(list));
return;
}

for (int i = start; i <= n-k+1; i++){
list.add(i);
backTrack(list, i+1, n, k-1);
list.removeLast();
}
}
}