递归

思想:一个大问题,是通过子问题尝试的方式来解决的。

image.png

EG1:求n!的结果

思路:

如果用递归的思想,就把他划分为n*(n-1)!

代码
 public static long getFactorial1(int n) {
        if (n == 1) {
            return 1L;
        }

        return (long) n * getFactorial1(n - 1);
    }

    public static long getFactorial2(int n) {
        long result = 1L;
        for (int i = 1; i <= n; i++) {
            result *= i;
        }
        return result;
    }

    public static void main(String[] args){
        int n = 6;
        System.out.println(getFactorial1(n));
        System.out.println(getFactorial2(n));
    }



EG2:汉诺塔问题

image.png

汉诺塔问题即,一个杆子上有从上到下按照从小到大排序的圆盘,现在有三个杆子,想要把一个杆子上的圆盘移动到另一个杆子,移动过程中不允许出现大圆盘压小圆盘,可以从左杆子直接移动到右杆子这种操作

思路:

比如想把左边的圆盘全部移动到右边圆盘上,右如下过程
1.把左圆盘的n-1个移动到中圆盘
2.把做原盘的第n个移动到右圆盘
3.把中的n-1个圆盘移动到右圆盘
把过程拆分无非就是六个过程,盘子从左到右,从左到中,从中到右,从中到左,从右到中,从右到左,实现如下,只实现一个,剩下同理,互相调用即可

    public static void moveLeftToRight(int n){
        if (n ==1){
            //即左杆子上只有一个圆盘,直接移动即可
            System.out.println("move" + n +"from left to right" );
        }

        moveLeftToMid(n-1);
        System.out.println("move" + n +"from left to right");
        moveMidtoRight(n-1);
    }

上面的思路是拆分到具体的过程,实现简单的方法是,把左中右三个杆子的思想去掉,把三个杆子分别看成from,to,help,from是盘子原来的杆子,to是要去的杆子,help是需要经过的中间杆子(比如n个盘子从左到右,就需要经过中间的这个help杆子实现),有了这三个杆子后,不管从哪到哪,都是from杆子到to杆子的过程,整体的过程就变成了把n-1先移动到help杆子,再把n从from杆子移动到to,在把n-1从help移动到to即可

代码:

  public static void Hanoi(int n){
        if (n>0){
            func(n,"left","mid","right");
        }
    }

    public static void func(int n,String from,String help,String to){
        if (n==1){
            System.out.println("move from" + from + "to" + to);
        }else {
            func(n-1,from,to,help);
            func(1,from,help,to);
            func(n-1,help,from,to);
        }
    }

注意一下这里的help杆子,只是代表他所起的一个作用,比如你在实现把n个盘子从from到to的时候,子过程需要把n-1从from到help,这一步怎么实现呢,就得把n-2个先从from移动到to,这里的to起到的作用就是help的作用。




EG3:

题目:子序列,比如{a,b,c}的子序列是a,b,c,ab,abc,bc,ac,空。必须是按顺序的才算子序列
image.png
思路:打印过程因为是按顺序的,所以可以从第一个元素开始看成一个二叉树,左分支是打印,右分支是不打印,如下图
image.png

形成这样一个二叉树后,需要打印它,思路是把二叉树看成一个数组,打印数组,打印方法:
1.如果数组下标没有移动到空即最后一个元素的下一个元素,下标就加一,直到下标为空,打印当前的,如下图


image.png

下标移动到了C后面,即空,打印abc
2.然后把c位置的数用一个临时变量存储起来,把c位置置零,然后仔打印
3.重复如上过程,即触底打印,打印后把当前i位置的数置零,再触底打印的过程

代码:
    public static void printAllSubsquence(String str) {
        char[] chs = str.toCharArray();
        process(chs, 0);
    }

    public static void process(char[] chs, int i) {
        if (i == chs.length) {
            System.out.println(String.valueOf(chs));
            return;
        }
        process(chs, i + 1);
        char tmp = chs[i];
        chs[i] = 0;
        process(chs, i + 1);
        chs[i] = tmp;
    }

    public static void main(String[] args) {
        String test = "abc";
        printAllSubsquence(test);
    }

经观察发现,如上实现过程实际上是吧二叉树最底层所代表的累计结果从左到右打印了
要注意递归跳跃信任,就是字面的意思要相信递归跳跃是对的,对于此题,无非就是两个过程,第一个是有的话一直触底打印,然后再出没有的情况,没有的情况怎么构造呢,就是把那个位置用临时变量存储,然后置零就构造出了,这两个情况构成了所有情况。




EG4:

题目:
image.png

即比如{a,b,c} 全排列是abc,acb,bac,bca,cab,cba

思路:

还是上面说的整体的问题划分成小的问题,然后重组,这个题就可一看成,选定第一个位置,然后全排列剩下的位置,这样的递归,在实现的时候怎么实现呢,就是以第一个位置为基点,全排列后面面的,全排列后,把第一个位置的数换成后面的数,再递归就可以了。比如abc,选定a,然后全排列bc,
然后交换ab的位置,bac这个顺序,再执行第一步的过程即可。

代码:
 public static void printAllPermutations1(String str) {
        char[] chs = str.toCharArray();
        process1(chs,0);
    }

    public static void process1(char[] chs, int i) {
      if (i==chs.length){
          System.out.println(String.valueOf(chs));
      }

      for (int j = i;j<chs.length;j++){
          swap(chs,i,j);
          process1(chs,i+1);
          swap(chs,i,j);
      }
    }

    public static void swap(char[] chs, int i, int j) {
        char tmp = chs[i];
        chs[i] = chs[j];
        chs[j] = tmp;
    }



EG5:

题目:
image.png
思路:

只需再例四的基础上加一个判断头位置的元素是否重复出现过,如果不重复出现再全排列,代码中用hashset来检测是否包含

代码:
 public static void printAllPermutations2(String str) {
        char[] chs = str.toCharArray();
        process2(chs, 0);
    }

    public static void process2(char[] chs, int i) {
        if (i==chs.length){
            System.out.println(String.valueOf(chs));
        }

        HashSet<Character> set = new HashSet<>();
        for (int j = i;j<chs.length;j++){
            //这里注意,判断条件因为交换后j位置就变成了头所以,是判断是否包含j位置元素去重
            if (!set.contains(chs[j])){
                set.add(chs[j]);
                swap(chs,i,j);
                process2(chs,i+1);
                swap(chs,i,j);
            }

        }
    }

    public static void swap(char[] chs, int i, int j) {
        char tmp = chs[i];
        chs[i] = chs[j];
        chs[j] = tmp;
    }

    public static void main(String[] args) {
        String test1 = "abc";
        printAllPermutations1(test1);
        System.out.println("======");
        printAllPermutations2(test1);
        System.out.println("======");

        String test2 = "acc";
        printAllPermutations1(test2);
        System.out.println("======");
        printAllPermutations2(test2);
        System.out.println("======");
    }

EG6:

题目:
image.png
思路:分析,即如果求第N年牛的数量,F(n)=F(n-1)+F(n-3)
代码:

    public static int cowNumber1(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2 || n == 3) {
            return n;
        }
        return cowNumber1(n - 1) + cowNumber1(n - 3);
    }

EG7

题目:告诉你一个数字串,能转变成多少种字母串,有多少种转换方式,数字串对应1-a,2-b等

例如1111可以转变成aaaa,aka,kaa,kk,共四种解法


image.png

EG8:

题目:
image.png
思路:

构造共两个函数,一个函数是抽取栈底元素(获得并删除),另一个就是开始逆序,递归过程。


image.png

image.png
代码:
  public static void reverse(Stack<Integer> stack){
        if (stack.isEmpty()){
            return;
        }
        int last = getAndRemoveLastElements(stack);
        reverse(stack);
        stack.push(last);
    }

    public static int getAndRemoveLastElements(Stack<Integer> stack){
        int res = stack.pop();
        if (stack.isEmpty()){
            return res;
        }else {
            int last = getAndRemoveLastElements(stack);
            stack.push(res);
            return last;
        }

    }
    public static void main(String[] args) {
        Stack<Integer> test = new Stack<Integer>();
        test.push(1);
        test.push(2);
        test.push(3);
        test.push(4);
        test.push(5);
        reverse(test);
        while (!test.isEmpty()) {
            System.out.println(test.pop());
        }

    }

以上就是递归及其思想,主要锻炼的是递归感觉,就是怎么把一个大过程分解成小过程,在合并

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351