zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    zbb20180930 设计模式-单例模式
    zbb20180930 代理模式 -静态代理-jdk动态代理-cglib动态代理
    zbb20180929 thread java并发编程之Condition
    zbb20180929 thread 自旋锁、阻塞锁、可重入锁、悲观锁、乐观锁、读写锁、对象锁和类锁
    zbb20180929 thread notify()与notifyAll()的区别
    26、Jquery 基础
    25、Javascript 事件
    24、Javascript BOM
    23、Javascript DOM
    22、正则表达式
  • 原文地址:https://www.cnblogs.com/lyz1995/p/7722908.html
Copyright © 2011-2022 走看看