-
递归,自认为最重要的就是递归和回溯
-
递归:就是"深入",通过有限次"相同操作",可以使解决的问题回到最简单的基本模型。
就比如:要计算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]));
}
}