递归问题

311 阅读7分钟

递归问题

1.递归思想:

重复的执行方法的调用:先递后归;

把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题,在逐步求解小问题后,再返回(回溯)得到大问题的解。递归算法设计的关键在于找出递归关系(方程)和递归终止(边界)条件。递归关系就是使问题向边界条件转化的规则。递归关系必须能使问题越来越简单,规模越来越小。递归边界条件就是所描述问题最简单的、可解的情况,它本身不再使用递归的定义。

2.递归注意事项:

1.递归的关键:

是找到出口和规程序的规律;

2.递归方法使用规则:

递归使用方法规则://1.执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
//2.方法的局部变量是独立的,不会相互影响;(因为在独立的栈空间内);
//3.若传入的是引用类型(数组,对象)则会共享(即会相互影响);
//4.递归必须向退出递归的条件逼近,否则就是死递归;
//5.当方法执行完毕或遇到return时,就会返回,遵守谁调用就返回给谁;

3.递归实例:

a.:阶乘问题:

1.
   // 思路:eg:如果我想要求5的阶乘,我只要求出4!然后再乘5即可,即4!*5,同理如果我要求4!只需求出3!之后再乘4即可.....
  //直到求到1!即1,找到递归的出口(即递的过程),之后再不断返回给调用处(即归的过程);
/*public class recursion {
    public static void main(String[]ages)
    {
        T a=new T();//创建对象;
        int m=a.jc(5);//调用方法;使用接收返回的值;
        System.out.println(m);//输出;
    }
}
class T {
    public int jc(int n) { // 1.创建方法:实现递归行为,2.返回类型int(因为阶乘为整数),3.形参列表:传入n(即所要求的数)
        if (n == 1) {   //递归出口:当n==1时直接输出结果为1;
            return 1;
        } else {
            return jc(n - 1) * n;//递归调用 
        }
    }
}

b:斐波那契:

使用递归方法求出斐波那契数列的第n项:
斐波那契数列(兔子数列):1123581321...
    思路:1.第一项和第二项结果都为1,作为递归的出口;
         2.找到数列的规律:即从第三项开始后一项=前两项之和;!!!即f(n)=f(n-1)+f(n-2);


public class recursion {
    //编写1个main方法;
    public static void main(String[]ages)
    {
        T a=new T();//创建T的·对象·
        int res=a.fib(7);//调用fib方法;
        System.out.print(res+" ");//输出
    }
}
class T{
    public int fib(int n)//创建方法:实现递归的行为
    {
        if(n==1||n==2){ //1.当n=1时fib=1;当n=2时,fib=2;递归的出口;
            return n;
        }else{
            return fib(n-1)+fib(n-2);//2.当n大于3时返回:fib=前两项相加;
        }
    }
}

c:猴子吃桃:

猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个,求第1-10天内某一天的桃子数;
    思路分析:1.因为只知道第10的桃子个数:1个,要推出之前天数的桃子数->:所以要倒推!!!;eg:day10=1/2(day9)-1;-->
        所以day9=(day10+1)*2//2.最后一天(第10天):1个桃;
//第9天:(day10+1)*2
//第8天:(day9+1)*2
//规律:前一天桃子=(后一天的桃子+1)*2;
//要求出第一天的桃子,得先求出第二天的桃子,要求出第二天的桃子得先求出第3天的桃子,形成递归
        3.//代码实现:
    public class recursion {
    public static void main(String[]ages)//创建main方法;
    {
       T a =new T();//创建对象 a;
       int res=a.pitch(1);//以要求第一天桃子为例:所以形参要传入1,又因为返回类型为int,可以使用中间变量res接收返回的值
       System.out.println(res);//输出
        //或者也可直接输出System.out.println(a.pitch(1));
    }
}
class T{
    public int  pitch(int day){//创建pitch方法:用于实现递归求每天的桃子
        //因为要求不同天的桃子数,所以day作为参数传入
        if(day==10){
            return 1;
        }else{
           return (pitch(day+1)+1)*2;//规律
        }
    }
}

    

d:迷宫问题:

//思路:1.看到此情景:行列排布会想到使用二维数组:所以制作整体框架使用二维数组;8行7列;
       2.图中:有障碍物和可通行位置,可以分别使用01表示
       3.由图可知第一行,第一列,最后一行,最后一列全为障碍物:可以用for循环全都赋值为1(表示有障碍物);
         然后图中可知:还有两个区域为障碍物,所以单独赋值为14.到现在已经可以生成地图的初始情况;
       5.现在进行找路:
           a:前提:
           为方便找路即标记:我们使用2表示为通路,3表示是走过且为死路,
           所以如果该条路是通路:走一步就标记一个2;
           如果是死路:则标记3;
           b:递归找路:因为要找到下一步要先确定前一步是否为通路:
                      找路策略:上下左右顺序可随机(我们以下左右上为例);
        6.因为要使用递归:1.首先要找递归出口:即如果出口处即arr[6][5]为通路(2)即证明找到了一条通路;
                        2.之后再根据找路策略寻找路:该条路通路就走一个标记一个2,如果走不通就标记3//代码实现:
           public class recursion0 {
    public static void main(String[]ages)
    {
        int [][]map=new int [8][7];//整体框架为一个8行7列二维数组,创建二维数组;
        int i,j;
        //使用0表示无障碍物,1表示有障碍物;
        for(i=0;i<7;i++)
        {
            map[0][i]=1;//因为第一行全部为障碍物,所以行不变,列循环,赋值为1;
        }
        for(i=0;i<7;i++)
        {
            map[7][i]=1;//因为第8一行行全部为障碍物,所以行不变,列循环,赋值为1;
        }
        for(i=0;i<8;i++)
        {
            map[i][0]=1;//因为第一列全为障碍物,列不变,行变;行循环,赋值为1;
        }
        for(i=0;i<8;i++)//
        {
            map[i][6]=1;//因为第7列全为障碍物,列不变,行变;行循环,赋值为1;
        }
        System.out.println("-----当前地图情况是L:-----");
        for(i=0;i<8;i++)
        {
            for(j=0;j<7;j++)
            {
                System.out.print(map[i][j]+" ");
            }
            System.out.println();
        }
        T t1=new T();//创建一个对象;
        t1.findway(map,1,1);//调用对象;
        System.out.println("------找路情况如下-----");
        for(i=0;i<8;i++)
        {
            for(j=0;j<7;j++)
            {
                System.out.print(map[i][j]);      //输出;
            }
            System.out.println();
        }
    }
}

class T {
递归找路:0表示可以走,1表示障碍物体,2表示可以走通,3表示走过但是是死路;
    public boolean findway(int map[][], int i, int j) { //1.findway方法专门用来招路;2.如果找到就返回true,否则返回false;
        if (map[6][5] == 2)//!!!!!a:递归出口:
            // :如果map[6][5]==2 说明这是一条通路已经找到了!!;那就返回true;// 3.map表示二维数组(迷宫);i,j表示老鼠位置,初始化的位置为(1,1)
        {
            return true;       //!!!!!!!
        } else {           //b:(else)否则就继续找:那没找到是什么情况呢,他现在的位置可以分为分为0,1,2,3
            if (map[i][j]==0)//c:如果当前位置map[i][j]==0说明现在可以走(还没走过)
            //使用找路策略(eg:下上左右):
            {
                map[i][j]=2;//使用招路策略,设置map[1][1]=2,假定他可以走通,来确定该位置是否真的可以走通;
                if(findway(map,i+1,j)){//下
                    return true;
                }else if(findway(map,i,j+1))//右               找路策略;
                {
                    return true;

                }else if(findway(map,i-1,j))//上
                {
                    return true;
                }else if(findway(map,i,j-1))//右
                {
                    return  true;
                }else{
                    //上下左走都不可标记3;
                    map[i][j]=3;
                    return false;
                }

            } else {//d:如果最后map[6][5]!=2,代表出不去了;没有出口;
                ////如果当前位置map[i][j]!=0,那么它有三种情况(1,2,3)
                 //1代表障碍物,3代表死路,!!!2代表已经测试过了就不要测了!!!-->>所以都返回false
                return false;
            }
        }
    }
}