递归的‘浅’理解

  • 递归,自认为最重要的就是递归和回溯

    • 递归:就是"深入",通过有限次"相同操作",可以使解决的问题回到最简单的基本模型。

      就比如:要计算3的阶乘,就要深入到2的阶乘,最后深入到简单的1的阶乘,当然最后要通过回溯解决问

      题,这样就将复杂重复的问题通过有限步骤的递归调用,就能达到问题的简单的形式。

    • 回溯:就是利用上一层的结果,来提供在本层中所缺少的参数。还拿3的阶乘举例子,在本层中,3要×2×1,即3前

      面所有数的乘积,但是2在本层的参数中没有给出,就只能从递归的返回值获取,进入下一层递归,没有

      1,继续进入,遇到1返回,这样,2就可以从返回值中获取1,同理,3可以从返回值中获取2,这样就计算

      了3的阶乘。

    • 代码如下

      java 复制代码
       @Test
       public void test(){
           System.out.println(getFactorial(9));  //362880
       }
       ​
       public long getFactorial(long num){
           if(num == 1){
               return 1;
           }
       ​
           //从返回之中获取在本层所需的元素(即为当前num的前面所有元素的乘积)
           long numPer = getFactorial(num-1);
       ​
           //计算,本层的 乘上 num 前面的所有乘积就好了
           long res = num * numPer;
       ​
           return res;
       }
  • 另一种理解方式就是,这个函数编写时,看作是已经实现的函数,相信自己的这个函数能解决或提供自己在本层中获取不到或解决不了的问题(虽然通常很难)

    递归的其他用处

  • 二叉树的遍历

    java 复制代码
     /*递归调用的深度优先搜索*/
     public void show(TreeNode root,List<Integer> list){
         if(root == null){
             return;
         }
         
         /*先序遍历,先左后右*/
     ​
         //先遍历左边
         show(root.left,list);
     ​
         /*中序遍历,先左后右*/
     ​
         //遍历右边
         show(root.right,list);
     }
     ​
     /*递归调用的广度优先搜索*/
     public void show(TreeNode root,int level){
             if(level == list.size()){
                 //当层数等于list的size时,说明该层还没有添加进去,需要添加一个新的list
                 list.add(new ArrayList<>());
             }
             
             //对每个元素的所在层进行归类
             list.get(level).add(root.val);
     ​
             if(root.left!= null) {
                 show(root.left, level + 1);
             }
     ​
             if(root.right!= null) {
                 show(root.right, level + 1);
             }
         }
  • 图论的巧用

    java 复制代码
     @Test
     public void test(){
         char[][] c = {
             {'1','1','0','0','0'},
             {'1','1','0','0','0'},
             {'0','0','1','0','0'},
             {'0','0','0','1','1'}
         };
         System.out.println(numIslands(c));
     }
     ​
     public int numIslands(char[][] grid) {
         int res = 0;
         int maxJ = grid[0].length;
         int maxI = grid.length;
         for (int i = 0; i < grid.length; i++) {
             for (int j = 0; j < grid[i].length; j++) {
                 if(grid[i][j] == '1'){
                     setFlag(grid,i,j,maxJ,maxI);
                     res++;
                 }
             }
         }
         return res;
     }
     ​
     public void setFlag(char[][] root,int i,int j,int maxJ,int maxI){
     ​
         if(i >= maxI || j >= maxJ || i < 0 || j < 0 || 
            root[i][j] == '0' || root[i][j] == '9'){
             return;
         }
     ​
         root[i][j] = '9';
     ​
         //从左边查找
         setFlag(root,i,j-1,maxJ,maxI);
         //从上边查找
         setFlag(root,i-1,j,maxJ,maxI);
         //从下边查找
         setFlag(root,i+1,j,maxJ,maxI);
         //从右面查找
         setFlag(root,i,j+1,maxJ,maxI);
     }
  • 回溯
java 复制代码
 @Test
 public void test(){
     int[] a = {1,2,3};
     permute(a);
 }
 ​
 public List<List<Integer>> permute(int[] nums) {
     List<List<Integer>> list = new ArrayList<>();
     List<Integer> q = new ArrayList<>();
 ​
     for (int num : nums) {
         q.add(num);
     }
 ​
     //我给你一个数组和要获取所有的排列组合
     myPermute(q,list,0,nums.length);
     return list;
 }
 ​
 public void myPermute(List<Integer> q,List<List<Integer>> list,int first,int len){
 ​
     //所有的数都排完了
     if(first == len){
         list.add(new ArrayList<Integer>(q));
     }
 ​
     //刨析所有的排列,
     for (int i = first; i < len; i++) {
         //维护动态数组,每次交换一个
         Collections.swap(q,first,i);
         //继续递归下一个数,我要这个新的交换的数的所有排列组合
         myPermute(q,list,first+1,len);
         //撤销操作
         Collections.swap(q,first,i);
     }
 }
 ​
 ​
 //====================================================================================
 ​
 ​
 @Test
 public void test(){
     System.out.println(subsets(new int[]{1,2,3,4,5}));
 }
 public List<List<Integer>> subsets(int[] nums) {
     List<Integer> list = new ArrayList<>();
     List<List<Integer>> res = new ArrayList<>();
     res.add(new ArrayList<>());
     getSon(nums,0,list,res);
     return res;
 }
 ​
 public void getSon(int[] father,int p,List<Integer> list,List<List<Integer>> res){
     for (int i = p;i < father.length;i++) {
         list.add(father[i]);
         res.add(new ArrayList<>(list));
         getSon(father, i + 1, list,res);
         list.remove(Integer.valueOf(father[i]));
     }
 }
相关推荐
路在脚下@9 分钟前
spring boot的配置文件属性注入到类的静态属性
java·spring boot·sql
森屿Serien12 分钟前
Spring Boot常用注解
java·spring boot·后端
轻口味39 分钟前
命名空间与模块化概述
开发语言·前端·javascript
苹果醋31 小时前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
晓纪同学2 小时前
QT-简单视觉框架代码
开发语言·qt
威桑2 小时前
Qt SizePolicy详解:minimum 与 minimumExpanding 的区别
开发语言·qt·扩张策略
Hello.Reader2 小时前
深入解析 Apache APISIX
java·apache
飞飞-躺着更舒服2 小时前
【QT】实现电子飞行显示器(简易版)
开发语言·qt
明月看潮生2 小时前
青少年编程与数学 02-004 Go语言Web编程 16课题、并发编程
开发语言·青少年编程·并发编程·编程与数学·goweb
明月看潮生2 小时前
青少年编程与数学 02-004 Go语言Web编程 17课题、静态文件
开发语言·青少年编程·编程与数学·goweb