• lecture-7 递归


    1、例题--排列 Permutation 
    Given a collection of distinct numbers, return all possible permutations.
    For example,
    [1,2,3] have the following permutations:
    [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1].
    public List<List<Integer>> permute(int[] nums) {
    // Implement this method.
    }

    1)边界条件:组合问题,输入为空,输出为空;其他情况都是正常的。

    2)思路:第一个位置先选一个数,第二位置从剩下的两个数里面选一个数,第三个位置只能选最后一个数。

    那么N个数的Level-N问题这样化简:第一个位置从N个数里面选择一个,剩余N-1位置和N-1个数,生成一个Level-(N-1)的问题,形成递归。

    3)代码实现

    public List<List<Integer>> permute(int[] nums) {
      List<List<Integer>> numList = new ArrayList<Integer>(); ///错误的new ArrayList<ArrayList<Integer>>()

      Arrays.sort(nums);//排序有什么用?跟大小没有关系.. 有重复数字的情况会有用。

      for (int i = 0 ; i < nums.length; i++) {

        numList.add(nums[i]);  ///将数组转换为Arraylist,方便后面操作

      }

       return permutes(new ArrayList<Integer>(); numList);

    }

      /*先实现递归函数主体*/

      public List<List<Integer>> permutes(ArrayList<Integer> cur, ArrayList<Integer> nums) {

        List<List<Integer>> results = new ArrayList<ArrayList<Integer>>();

        if (0 == nums.size()) {

          ///ArrayList<Integer> result = new ArrayList<>(cur);  ///不需要这一行,因为上一层函数已经申请了新的内存空间

          results.add(result);

          return results;

        }

        for (int i = 0; i < nums.size(); i++) {

          List<Integer> newCur = new ArrayList<>(cur);

          newCur.add(nums.get(i));

          List<Integer> newNum = new ArrayList<>(nums);

          newNums.remove(i); 

             result.addAll(permutes(newCur, newNum));

        }

        return results;

      }

    4)时间复杂度:O(n!);空间复杂度:O(n!)---空间复杂度似乎不准

    5)其他解法

    a)

    public List<List<Integer>> permute(int[] nums) {
      List<List<Integer>> numList = new List<Integer>();

      for (int i = 0 ; i < nums.length; i++) {

        numList.add(nums[i]);

      }

       return permutes(new List<Integer>(); numList);

    }

    public List<List<Integer>> permutes(List<Integer> cur, List<Integer> num) {

      List<List<Integer>> results = new ArrayList<Integer>();

      if (0 == num.size()) {

        List<Integer> result = new ArrayList<Integer>(cur); //这里申请新内存保持结果,因为上层函数没有申请,只有一个cur在传递。

        results.add(result);///可以简化一下 results.add(new ArrayList<Integer>(cur))

        return results;

      }

      for (int i = 0; i < num.size(); i++) {

        cur.add(num.get(i));

        num.remove(i);

        results.addAll(permutes(cur, num));

        num.add(cur.get(cur,size() - 1));///没有申请新内存,所以要恢复现场

        cur.remove(cur.size() - 1);

      }

      return results;

    }

    b) 

    public ArrayList<ArrayList<Integer>> permute(int[] num) {

      ArrayList<ArrayList<Integer>> results = new ArrayList<Integer>();

      Arrays.sort(nums);

      return permutes(new ArrayList<Integer>(), nums);

    }

    public ArrayList<ArrayList<Integer>> permutes(ArrayList<Integer> cur, int[] nums) {

      ArrayList<ArrayList<Integer>> results = new ArrayList<Integer>();

      if (cur.size() == nums.length) {

        ArrayList<Integer> result = new ArrayList<Integer>(cur);

        results.add(result); ///可以简化一下 results.add(new ArrayList<Integer>(cur))

        return results;

      }

      for (int i = 0; i < nums.length; i++) {

        if (!cur.contains(nums[i])) {

          cur.add(num[i]);

          results.addAll(permutes(cur, nums));

          cur.remove(cur.size() - 1);   

        }

      }

    }

    c)Use the num array to serve as the "cur"

    [0..index-1] means we have already set the first index
    numbers
    [index..length-1] are the numbers that we haven't set
    Example: [4, 3, 5, 8, 1]
    choose 8, then swap (4, 8) => [8, 3, 5, 4, 1]
    choose 3, do nothing => [8, 3, 5, 4, 1]
    choose 1, then swap (5, 1) => [8, 3, 1, 4, 5]
    choose 5, then swap (4, 5) => [8, 3, 1, 5, 4]
    choose 4, do nothing, => [8, 3, 1, 5, 4]

     public ArrayList<ArrayList<Integer>> permute(int[] nums) {

      ArrayList<ArrayList<Integer>> results = new ArrayList<Integer>();

      Arrays.sort(nums);

      permutes(results, nums, 0);

      return results;

    }

    public void permutes(ArrayList<ArrayList<Integer>> results, int[] nums, int index) {

      if (index == nums.length) {

        ArrayList<Integer> result = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {

          result.add(nums[i]);

        }

        results.add(result);

        return;

      }

      for (int i = index; i < nums.length; i++) {

        swap(nums, index, i);

        permutes(results, nums, index + 1);

        swap(nums, i, index);    

      }

      return;

    public void swap(int[] nums, int i, int j)

    2、组合--Combination

    Given a collection of distinct numbers, return all possible combinations.
    For example,
    [2, 6, 8] have the following permutations:
    [], [2], [6], [8], [2, 6], [2, 8], [6, 8], [2, 6, 8].
    public List<List<Integer>> combine(int[] nums) {
    // Implement this method.
    }

    1)边界条件:空集合;输入为空能在正常流程里面处理吗?

    2)思路:对于第一个数2有两种情况,选择或者不选择;然后再对[6,8]进行组合。那么对于Level-N的问题,先对第一个数进行选择/不选择,然后对剩余N-1个数进行组合,这样就化为Level-(N-1),形成了递归。

    3)代码实现:

    public List<List<Integer>> combine(int[] nums) {

      return combines(new ArrayList<Integer>(), nums, 0);

    }

    public List<List<Integer>> combines(List<Integer> cur, int[] nums, int index) { ---把结果当做出参

      List<List<Integer>> results = new ArrayList<>();

      if (index == nums.length) {

        results.add(new ArrayList<Integer>(cur)); //上一层没有申请内存,这一层申请

        return results;  

      }

      results.addAll(combines(cur, nums, index + 1));

      cur.add(nums[index]);

      results.addAll(combines(cur, nums, index + 1));

      cur.remove(cur.size() - 1); //恢复现场

    }

    4)时间复杂度:O(2^n);空间复杂度:O(2^n)?

    其他解法:把结果当做入参

    public List<List<Integer>> combine(int[] nums) {

      List<List<Integer>> results = new ArrayList<>();

      combines(results, new ArrayList<Integer>(), 0);

      return results;

    }

    public void combines(List<List<Integer>> results, List<Integer> cur, int[] nums, int index) {

      if (index == nums.length) {

        results.add(cur);//直接添加,上一层已经申请了新内存。

        return;

      }

      List<Integer> newCur1 = new ArrayList<>(cur);

      combines(results, newCur1, nums, index + 1);

      List<Integer> newCur2 = new ArrayList<>(cur);//得申请两个新内存,不然也会互相覆盖。申请两个就不用恢复现场了。

      newCur2.add(nums[index]);

      combines(results, newCur2, index + 1);

      return;

    }

  • 相关阅读:
    MongoDB:数据库管理
    MongoDB:用户管理
    MongoDB:入门
    彻底透析SpringBoot jar可执行原理
    轻松了解Spring中的控制反转和依赖注入(一)
    领域驱动最佳实践--用代码来告诉你来如何进行领域驱动设计
    血的教训--如何正确使用线程池submit和execute方法
    领域驱动设计之实战权限系统微服务
    为什么我们需要领域驱动设计
    【Go入门学习】golang自定义路由控制实现(二)-流式注册接口以及支持RESTFUL
  • 原文地址:https://www.cnblogs.com/shihuvini/p/7436356.html
Copyright © 2020-2023  润新知