递归的基本用法以及全排列

递归解释:就是使用自己的方法调用自己,直至达到出口的条件,才会终止对自己的调用

递归三要点

主要思路就是将大问题转化成小的子问题,在这个过程中,通常会有一些变化的量,这些量通常会作为参数进行变化。

1.找重复:找到一种划分方法

找到递推公式或者等价转换

以求n的阶乘为例:

要找n的阶乘就要找n-1的阶乘

2.找变化

由n变化到n-1

3.找边界

即找程序的出口,若没有出口则会一直调用自己,导致栈溢出

要找的边界就是在满足什么条件时结束该程序。

切蛋糕思维

  
案例:求阶乘
    private static int f(int n) {
        int result = 1;
       if (n == 1) {            
           return result;
        }
        result = n * f(n-1);
        return result;
    }
    输出x-->a之间的数
    private static void f1(int x, int a){
        if (a == x-1) {
            return;
        }
        System.out.println(a);
        f1(x,a-1);
    }
        求数组的和
    private static int f2(int[] arr,int begin){
            if (begin == arr.length) {
                return 0;
            }
            return arr[begin] + f2(arr,begin+1);
    }
        反转字符串
   private static String f3(String str,int end){
        if (end == -1) {
                return "";
            }
        return str.charAt(end) + f3(str,end-1);
        }
一般的数学问题可以找递推公式,如:斐波那契数列和求最大公约数

二分查找的递归解法

等价于三个子问题

左边找(递归)

中间比

右边找(递归)

public class BinarySearch2 {
 
    public static int rank(int key,int[] arr,int start,int end){
        if(start >end){
            return -1;
        }
        int mid=start+(end-start)/2;
        if(key<arr[mid]){
            return rank(key,arr,start,mid-1);
        }else if(key>arr[mid]){
            return rank(key,arr,mid+1,end);
        }else{
            return mid;
        }
    }
    public static void main(String[] args) {
        int arr[]={0,1,3,5,6,7,8,8,9}; System.out.println("resultPosition="+rank(3,arr,0,8));
    }
}


递归解决全排列的问题

全排列的个数 n!;

通过迭代实现全排列:仅适用于长度为3或3以下的字符串

import java.util.ArrayList;
​
public class 全排列 {
    public static void main(String[] args) {
        String A = new String("ABC");
        int n = A.length();
        ArrayList<String> res = new ArrayList<>();
        //初始化res,里面包含一个元素空字符串
        res.add(A.charAt(0) +"");
        for (int i = 1; i < n; i++) {
            ArrayList<String> new_res = new ArrayList<>();
            char c = A.charAt(i);
            for (String str:
                 res) {
                String newStr = c+str;
                new_res.add(newStr);
                newStr = str + c;
                new_res.add(newStr);
                for (int j = 1; j < str.length(); j++) {
                    newStr = str.substring(0,j) +c +str.substring(j);
                    new_res.add(newStr);
                }
            }
            res = new_res;
        }
    }
}

通过递归来实现全排列

难点:如何实现多路递归

非字典序的全排列

在这个for循环里面先走完递归的循环,然后再进行下一个循环

即先纵后横

public class Main_2 {
    public static void main(String[] args) {
        perm(new int[]{1,2,3},0,2);
    }
    public static void perm(int[] array,int start,int end) {
        if(start==end) {//递归的一个支路走到底了,输出一个。
            System.out.println(Arrays.toString(array));
        } else {
            for (int i = start; i <= end; i++) {
                //1,2,3的全排列这块相当于将其中一个提了出来,下次递归从start+1开始
                swap(array,start,i);
                perm(array,start+1,end);
                //这块是复原数组,为了保证下次另外的同级递归使用数组不会出错
                //这块可以通过树来理解,每次回退一步操作,交换回去
                swap(array,start,i);//简称回溯
            }
        }
    }
    public static void swap(int[] array,int i,int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

没有维持字典序的原因

在交换的过程中[1,2,3]被换成了3[2,1]所以从第三次开始就不会再维持字典序,所以排出来的结果是321在前,312在后。

字典序全排列

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值