递归的‘浅’理解

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

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

      就比如:要计算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]));
     }
 }
相关推荐
k09334 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
激流丶11 分钟前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic
神奇夜光杯12 分钟前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
Themberfue15 分钟前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
plmm烟酒僧16 分钟前
Windows下QT调用MinGW编译的OpenCV
开发语言·windows·qt·opencv
测试界的酸菜鱼28 分钟前
Python 大数据展示屏实例
大数据·开发语言·python
让学习成为一种生活方式31 分钟前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言
晨曦_子画37 分钟前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
Black_Friend1 小时前
关于在VS中使用Qt不同版本报错的问题
开发语言·qt
南宫生1 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法