十分钟了解算法(1)——初始递归与分治

版权声明:本文为博主原创,未经博主允许不得转载。 https://blog.csdn.net/weixin_36904568/article/details/88741671

1. 递归

(一)递归与循环:

循环可以让性能变快,递归可以让程序容易理解。

(二)递归的特点:

  1. 子问题需与原始问题为同样的事,且更为简单;
  2. 不能无限制地调用本身,需有个出口,化简为非递归状况处理。

(三)递归的结构:

  1. 边界条件
  2. 递归前进段
  3. 递归返回段

当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

(四)递归的本质:调用栈

  1. 在计算机中调用函数F1时,计算机将F1压入栈中,为F1分配内存用于存储变量。
  2. 在函数F1中调用函数F2时,计算机将F2压入栈中,为F2分配内存用于存储变量。此时的F1暂停执行,转而执行F2.
  3. 函数F2完成返回后,计算机将F2弹出栈,F1继续执行。
  4. 函数F1完成返回后,计算机将F1弹出栈,程序结束。

(五)递归求解的步骤:

  1. 找重复(在重复中找到一种划分,通过递推公式或者等价转化成子问题)
  2. 找变化的量(变化的量通常是转化成参数的)
  3. 找到出口(根据参数变化规律找到边界条件)

(六):递归解决的问题

单层递归 —— n的阶乘问题
  1. 找重复:不断相乘
  2. 找变化:n会不断减1
  3. 找出口:n = 1
   public static int fac(int n){
        if(n == 0)
            return 0;
        if(n == 1)
            return 1;
        return n*fac(n-1);
    }
双分枝递归 —— 斐波那契数列:后一项为前两项的和的数列
  1. 找重复:不断对两个数求和
  2. 找变化:n不断减1和减2,找前两个数
  3. 找出口:n = 0
public static int fib(int num){
        if(num == 1)
            return 1;
        if (num == 0)
            return 0;
        return fib(num-1)+fib(num-2);
    }
双分枝递归 —— 上楼梯问题:

楼梯有n阶台阶,上楼可以一步上1阶,也可以一步上2阶,共有多少种不同的走法?

  1. 找重复:走楼梯每次都会上台阶
  2. 找变化:每上台阶,剩余台阶数会减少
  3. 找出口:当走完台阶时结束
  //走楼梯
    public static int walkUp(int all){
        if(all <= 0 )   //没有台阶
            return 0;
        if(all == 1)    //有一个台阶,只有1种走法
            return 1;
        if (all == 2)   //有两个台阶,可以走一步,也可以分别走两步
            return 2;
        return walkUp(all - 1)+walkUp(all -2);  //有多个台阶,则考虑走一个台阶的方法和走两个台阶的方法的并集
    }
汉诺塔问题

有a、b、c三个塔,初始状态是:在 a 塔上放了 n 个圆盘从上到下,从小到大。(大盘不允许放在小盘上)要求把 a 塔上的盘子放到 c 塔上。每次只能拿一个盘子。

解决:首先以c塔为中介,将前n-1个圆盘从a塔挪到b塔上。再将第n个圆盘从a移动到c塔上,最后以a塔为中介,将b塔上的n-1个圆盘移到c塔上。

  1. 找重复:不断的把圆盘,从一个塔移动到另一个塔(先从起点塔移到中间塔,再从中间塔移到终点塔)。
  2. 找变化:圆盘数量n不断减1
  3. 找出口: 当圆盘n = 1,移动最后一个盘
 public static void move(int n,char from, char temp,char to){
        if(n == 1)  //移最后一个,把圆盘从A移到C
        {
            System.out.printf("move the %d :%s-->%s%n",n,from,to);
        }
        else
        {
            move(n-1,from,to,temp);     //把A塔上编号1~n-1的圆盘移到B上,以C为辅助塔
            System.out.printf("move the %d :%s-->%s%n",n,from,to);  // 把第n个圆盘从A移到C
            move(n-1,temp,from,to);     //把B塔上编号1~n-1的圆盘移到C上,以A为辅助塔
        }
    }

2. 分治法

(一)分治的特点:

  • 原问题可以被分解成性质类似的子问题
  • 子问题互相独立,不存在依赖关系
  • 子问题的解能够协助原问题得到最终解

(二)分治的思想:分解

  1. 找出简单的基线条件,即把问题进行极限化。
  2. 通过递归不断将问题分解,缩小规模,直到找到符合的条件,也就是找到问题的极限。

(三)分治法求解的步骤

  1. 划分问题:整个问题划分成多个性质类似却互相独立的子问题。
  2. 递归求解:递归调用求解各个子问题。
  3. 合并问题:合并子问题的解,形成原始问题的解。

(四)分治法解决的问题

计算一组数的和
  1. 划分问题:要求一组数的和,把这组数分为一个数和一部分数求和
  2. 递归求解:不断把一部分数分解,直到只剩一个数,它就是这组数的和
  3. 合并问题:把所有组的数加起来就是结果
  //通过分治法计算一组数的和:如果数组中只有一个元素,那么它就是数组的和
    public static int sum(int[] arr){
        if(arr.length==1)   //递归结束的条件,数组只有一个元素
            return arr[0];
        else                //通过递归缩小数组的规模
            return arr[arr.length-1]+sum(Arrays.copyOf(arr,arr.length-1));
    }
求一组数的最大值
  1. 划分问题:要求一组数的最大值,把这组数分为一个数和一组数比较
  2. 递归求解:递归把剩下的一部分数分解,直到只剩一个数,它自己就是最大值
  3. 合并问题:把所有组的数互相比较就是结果
 //使用分治法找出一组数的最大值:如果数组中只有一个元素,则它自己就是最大值
    public static int find_max(int[] arr){
        if(arr.length==1)       //递归结束的条件:数组只有一个元素
            return arr[0];
        else                    //通过递归缩小规模
            return  Math.max(arr[arr.length-1],find_max(Arrays.copyOf(arr,arr.length-1)));
    }
二分法:
  1. 划分问题:通过中间值把记录分为两部分,分别找关键字。
  2. 递归求解:不断把记录的记录分为两部分,找关键字。
  3. 合并问题:在最后的记录中找到问题的解
 public static int binart_search(int[] arr,int key){
        int index = -1,low = 0,high = arr.length-1,mid = 0;
        while (low<=high)
        {
            mid = (low+high)/2;         //中间值
            if(arr[mid]>key)            //比中间的小,修改high
                high = mid-1;
            else if(arr[mid]<key)       //比中间的大,修改low
                low = mid+1;
            if (arr[mid]==key)          //命中
            {
                index = mid;
                break;
            }
        }
        return index;
    }
找硬币问题:

一共有m枚硬币,已知其中有一枚是假的,它比其他m-1枚都要轻。现在有一个天平,称多少次可以找到这枚硬币?

  1. 划分问题:把硬币堆分为3部分,分别称硬币堆。
  2. 递归求解:不断把硬币堆分为3部分,分别称硬币堆。
  3. 合并问题:如果天平平衡,那么假币一定在没称的那一堆里,如果天平不平衡,那么假币就在天平高起的那一堆里。

猜你喜欢

转载自blog.csdn.net/weixin_36904568/article/details/88741671