蓝桥杯-经典的递归问题(一)

来源:互联网 发布:网络基本知识子网 编辑:程序博客网 时间:2024/06/07 17:38

珍惜作者劳动成果 转载请注明出处

致谢蓝桥杯

取球问题

问题描述: 在n个球中, 任意取出m个(不放回), 求有多少种不同的取法.

求解思路:

  从题目上看, 这个问题对于递归来说似乎没有突破口, 找不到合适的相似性? 这就要发挥我们特长 – 想象!
  在进行想象之前需要先明确我们方法的参数 : int f (int n, int m) , n 个球中取m个 , f的返回值就是取法的种数
  好, 我们想象这n个球取1个特殊球, 那么我们要么取到这个球, 要么取不到这个球
  如果取到了这个特殊球, 则: f (n - 1, m - 1), 总数总是要减1, 因为取到了特殊球, 所以m-1,
  反之我们没有取到特殊球, 则; f(n - 1, m), 总数还是减1, 但是m的值不变
  此时我们就可以表达 f (n, m) = f (n - 1, m - 1) + f(n - 1, m)
  递归的形式已经出来了, 现在就差递归出口了!
  好, 看代码:
  

public static int f (int n, int m) {    //递归出口判断    if (n < m) {//不可能取到        return 0;    }    if (n == m) { //如果要取的球跟总球数相同, 那只有一种取法        return 1;    }    if (m == 0) { //还有, 如果取到最后, 那也只有一种取法, 返回1        return 1;    }    return f(n - 1, m - 1) + f(n - 1, m);// n 个球中取1个特殊球 取法划分: 取 | 不取}

全排列问题

> 问题描述: 求n个元素的全排列(把所有的排列形式都打印出来)

求解思路:
  
  不难发现, 有这么一个规律: 可以考虑把每个元素先放在开始这个位置, 把后面元素全排列
  但是我们需要循环遍历后面的每个字符, 所以外层需要套层循环, 并且有个”关注点” 作为起始位置 , 在递归前, 将”关注点”的元素交换到遍历的位置, 而且递归后要把位置上字符再交换回来, 这就是我们通常讲的回溯.
  接下来就要考虑出口问题了, 其实也不难想, 如果我们的要交换的位置到了最后是不是就要考虑交换了呢? 好, 我们思路缕清楚了.
  看代码前我先介绍一种高速交换元素位置的办法(应该快吧 ?):

//一种用位运算的交换方法private static void swap(char[] chs, int i, int j) {    if (i == j){        return;    }    chs[i] ^= chs[j];    chs[j] ^= chs[i];    chs[i] ^= chs[j];}

  接下就是我们的问题解决代码:

public static void f (char a[], int k) {    //递归出口, 如果关注点到了最后一个位置,就需要打印了    if (k == a.length-1){        System.out.println(Arrays.toString(a));    }    //从第k个开始到最后进行交换, 每交换一次开始递归, 递归结果返回后, 要再交换回来(回溯)    for (int i = k; i < a.length; i++) {        swap(a, k, i);        f(a, k + 1);//每递归一次就要, 就要把关注位置向前挪一位        swap(a, k, i);//一定不要忘记回溯    }}
1 0
原创粉丝点击