DFS习题复习

 

DFS(深度优先搜索)解题思路:recursion的思想。(常见题型:当题目要求穷举所有可能性时,多用DFS),解题思路分两步:

1:考虑总共recursion有几层

2:考虑每一层recursion内有多少个case

1.All Subsets

Given a set of characters represented by a String, return a list containing all subsets of the characters.

Assumptions

  • There are no duplicate characters in the original set.

​Examples

  • Set = "abc", all the subsets are [“”, “a”, “ab”, “abc”, “ac”, “b”, “bc”, “c”]
  • Set = "", all the subsets are [""]
  • Set = null, all the subsets are []

解题思路:1:recursion层数为:set.length()

               2:每层case,只需考虑当前layer对应的character存在或不存在

recursion tree 为(以“abc”为例):                 {}

                     "a" level:                   {a}                 {}

                     "b"level:            {ab}        {a}      {b}       {}  

                     "c"level:       {abc}  {ab} {ac} {a} {bc} {b} {c} {}

由recursion tree可以看出,当递归进行到最后一层时,所有得leaf node就为所有得结果:

Java Solution:

 1 public List<String> subSets(String set) {
 2    List<String>result=new ArrayList<String>();
 3    if(set == null){
 4      return result;
 5    }
 6    helper(set, new StringBuilder(), 0, result);
 7    return result;
 8   }
 9   private void helper(String set, StringBuilder sb, int layer, List<String>result){
10     if(layer == set.length()){
11       result.add(sb.toString());
12       return;
13     }
14     sb.append(set.charAt(layer));
15     helper(set, sb, layer+1, result);
16     sb.deleteCharAt(sb.length()-1);
17     helper(set, sb, layer+1, result);
18   }
All subsets

考虑存在重复元素的情况:

去重方法:

Solution1:如果数组是已经排序好的,我们可以比较容易的去处重复元素,在每一层layer进行完后,只需要跳到下一个和当前值不同的节点即可。

由于整个DFS的时间复杂度为O(2^n),因此可以先将传入数组排序后再进行DFS过程,由于排序时间复杂度仅为o(nlogn)因此并不影响整体的时间复杂度。

Solution2:如果不进行排序,也可以每层maintain一个hashset,存放之前层出现过的charater,跳过所有之前存在过的节点即可。

 1 public List<String> subSets(String set) {
 2         List<String> result = new ArrayList<String>();
 3         if (set == null) {
 4             return result;
 5         }
 6         if(set.length() == 0) {
 7             result.add("");
 8             return result;
 9         }
10         char[]array=set.toCharArray();
11         Arrays.sort(array);
12         set=new String(array);
13         helper(result,set,0,new StringBuilder());
14         return result;
15     }
16     private void helper(List<String>result,String set, int layer, StringBuilder sb) 
17        {
18         if(layer == set.length()) {
19             result.add(sb.toString());
20             return;
21         }
22         sb.append(set.charAt(layer));
23         helper(result,set,layer+1,sb);
24         sb.deleteCharAt(sb.length()-1);
25         while(layer < set.length()-1 && set.charAt(layer+1) == set.charAt(layer)) {
26             layer++;
27         }
28         helper(result,set,layer+1,sb);
29     }
All subsets2.

2.All Permutations:

Given a string with no duplicate characters, return a list with all permutations of the characters.

Examples

  • Set = “abc”, all permutations are [“abc”, “acb”, “bac”, “bca”, “cab”, “cba”]
  • Set = "", all permutations are [""]
  • Set = null, all permutations are []

解题思路:

1:总共层数,layer=set.length();

2:每层case:同subsets的区别在于,每个character仅是位置互换,而非考虑其存在不存在。因此在每一层recursion中,我们只需穷举所有可能在当前位置出现的character的可能性。具体的实现方法,将当前节点后的每个节点的值和当前节点swap,递归完后再swap回来再交换下一个节点,简称“swap来swap去”

PS:若题目要求需要考虑有重复元素的情况时,去重方法与上题完全相同,既可以从sort的角度去考虑,也可以用Hashset的方法。

Java Solution:

 1 public List<String> permutations(String set) {
 2   List<String>result=new ArrayList<String>();
 3   if(set==null){
 4     return result;
 5   }
 6   char[]c=set.toCharArray();
 7   helper(c, result, 0);
 8   return result;
 9   }
10   private void helper(char[]c, List<String>result,int index){
11     if(index == c.length){
12       result.add(new String(c));
13       return;
14     }
15     for(int i=index; i<c.length; i++){
16       swap(c, i, index);
17       helper(c, result, index+1);
18       swap(c, i, index);
19     }
20   }
21   private void swap(char[]array, int i, int j){
22     char temp=array[i];
23     array[i]=array[j];
24     array[j]=temp;
25   }
All permutation

3:All Valid Permutations Of Parentheses

Given N pairs of parentheses “()”, return a list with all the valid permutations.

Assumptions

  • N >= 0

Examples

  • N = 1, all valid permutations are ["()"]
  • N = 3, all valid permutations are ["((()))", "(()())", "(())()", "()(())", "()()()"]
  • N = 0, all valid permutations are [""]

解题思路:

1:总共有多少层? 总共层数为括号总数:n*2

2:每层有多少case? 与之前两题不同的是,本题需要考虑左括号和右括号添加priority的问题,既必须得保证,在每次添加右括号时,得保证之前添加的左括号个数大于右括号个数。既如果之前添加过的括号为“()”,在当前层仅能加左括号而不能加右括号,因此每层的case分为两个,既要么加左括号,要么加右括号。

Java Solution:

 1 public List<String> validParentheses(int n) {
 2    List<String>result=new ArrayList<String>();
 3    helper(n, 0, 0, result, new StringBuilder());
 4    return result;
 5   } 
 6   private void helper(int n, int left, int right, List<String>result, StringBuilder sb){
 7     if(left == n && right == n){
 8       result.add(sb.toString());
 9       return;
10     }
11     if(left < n){
12       sb.append("(");
13       helper(n, left+1, right, result, sb);
14       sb.deleteCharAt(sb.length()-1);
15     }
16     if(right < left){
17       sb.append(")");
18       helper(n, left, right+1, result, sb);
19       sb.deleteCharAt(sb.length()-1);
20     }
21   }
All valid parentheses

4:Combination of Coins

Given a number of different denominations of coins (e.g., 1 cent, 5 cents, 10 cents, 25 cents), get all the possible ways to pay a target number of cents.

Arguments

  • coins - an array of positive integers representing the different denominations of coins, there are no duplicate numbers and the numbers are sorted by descending order, eg. {25, 10, 5, 2, 1}
  • target - a non-negative integer representing the target number of cents, eg. 99

Assumptions

  • coins is not null and is not empty, all the numbers in coins are positive
  • target >= 0
  • You have infinite number of coins for each of the denominations, you can pick any number of the coins.

Return

  • a list of ways of combinations of coins to sum up to be target.
  • each way of combinations is represented by list of integer, the number at each index means the number of coins used for the denomination at corresponding index.

Examples

coins = {2, 1}, target = 4, the return should be

[

  [0, 4],   (4 cents can be conducted by 0 * 2 cents + 4 * 1 cents)

  [1, 2],   (4 cents can be conducted by 1 * 2 cents + 2 * 1 cents)

  [2, 0]    (4 cents can be conducted by 2 * 2 cents + 0 * 1 cents)

]

解题思路:

1:多少层?: coins.length 层(硬币种类数)每一层仅需考虑当前种类的硬币可能存在多少种情况

2:每层多少case?:每层case为每种硬币在当前target的条件下,所有可能出现的情况。比如: 当前剩余硬币为100, 当前硬币面值为3,那当前面值为3的硬币的所有可能性为0-100/3 次,分析时间复杂度时,取worst case,既面值最小硬币的情况,如target=100,最小硬币面值为1时,时间复杂度为o(100^coins.length)

Java Solution:

 1 public List<List<Integer>> combinations(int target, int[] coins){
 2      List<List<Integer>>result=new ArrayList<List<Integer>>();
 3    helper(target, coins, result, new ArrayList<Integer>(), 0);
 4    return result;
 5     }
 6     private void helper(int target, int[]coins, List<List<Integer>>result,
 7     List<Integer>list, int layer){
 8       if(layer == coins.length-1){
 9         if(target % coins[layer] == 0){
10           list.add(target/coins[layer]);
11           result.add(new ArrayList(list));
12           list.remove(list.size()-1);
13         }
14         return;
15       }
16       for(int i=0; i <= target/coins[layer]; i++){
17         list.add(i);
18         helper(target-(i*coins[layer]), coins, result, list, layer+1);
19         list.remove(list.size()-1);
20       }
21     }
Combinations Of Coins

5: N皇后问题

Get all valid ways of putting N Queens on an N * N chessboard so that no two Queens threaten each other.

Assumptions

  • N > 0

Return

  • A list of ways of putting the N Queens
  • Each way is represented by a list of the Queen's y index for x indices of 0 to (N - 1)

Example

N = 4, there are two ways of putting 4 queens:

[1, 3, 0, 2] --> the Queen on the first row is at y index 1, the Queen on the second row is at y index 3, the Queen on the third row is at y index 0 and the Queen on the fourth row is at y index 2.

[2, 0, 3, 1] --> the Queen on the first row is at y index 2, the Queen on the second row is at y index 0, the Queen on the third row is at y index 3 and the Queen on the fourth row is at y index 1.

 解题思路与之前题类似,还是分析两个条件:

1:总共有多少层?:显然有N层。

2:每层有多少个case? 每层理论上来说,需要考虑每一个位置,但是并不是所有的节点都valid,由于上下及斜线不能有重复节点,所以在每层递归到下一层前需要先判断该位置是否valid,时间复杂度为n!.

Java Solution:

 

 1 public List<List<Integer>> nqueens(int n) {
 2     List<List<Integer>>result=new ArrayList<List<Integer>>();
 3     helper(result, new ArrayList<Integer>(), n, 0);
 4     return result;
 5   }
 6   private void helper(List<List<Integer>>result, List<Integer>list, int n, int layer){
 7     if(n == layer){
 8       result.add(new ArrayList<Integer>(list));
 9       return;
10     }
11     for(int i=0; i<n; i++){
12       if(isValid(i, list)){
13         list.add(i);
14         helper(result, list, n, layer+1);
15         list.remove(list.size()-1);
16       }
17     }
18   }
19   private boolean isValid(int i, List<Integer>list){
20     if(list.isEmpty()){
21       return true;
22     }
23     int layer=0;
24     for(Integer in: list){
25       if(i == in || Math.abs(i-in) == Math.abs(list.size()-layer)){
26         return false;
27       }
28       layer++;
29     }
30     return true;
31   }
N Queens

 

posted @ 2017-10-24 12:16  想做码农的熊孩子  阅读(333)  评论(2编辑  收藏  举报