zoukankan      html  css  js  c++  java
  • 三行核心代码解决全排列问题

    早上还在床上的时候,用手机看到了博客园上一个全排列算法。刚才,出去晒了一下太阳,突然想起那个全排列算法,

    感觉还是比较的繁琐。回来后,我仔细分析了一个这个问题,觉得,实际上,3行代码就可以解决这个问题了。

    顺便,也说说,递归问题的一般解决思路吧。

    这个问题,非常明显,是一个 n! 复杂度的程序,如果是这样,基本上的递归结构是这样的。

    f(n) = n * f(n-1)

    看到这样的问题,典型的结构 应该就是 这样的结构:

    f(n)
    {
     for (i = 0; i < n; i++)

     {

         f(n-1)

     }
    }

    退出条件就是 n = 0;

    当然,递归问题,必须有:

    1. 结束条件

    2. 递推公式

    这样,首先看递推公式。

    首先对位置进行编号:(因为数组下标从 0开始,那就从0 开始吧)

    0, 1, 2, 3, 4, 5

    里面填一些数,显然,填什么不重要,假设

    a, b , c, d, e, f

    好了

    如果让问题规模小1 呢?

    很多递归问题,其实都是可以这样分析的,假设 n - 1 的都已经算好了,

    如果你没有思路,我刚开始也没有,其实,你只要在纸上画出 f(n-1) 的所有可能性(要按照一定的思路列出)。

    不要怕烦,写代码的思路就是这样出来的(当然,天才或许有灵感)

    a 没有:b , c, d, e, f

    b 没有:a, c, d, e, f

    c 没有:a, b, d, e, f

    d 没有: a, b, c, e, f

    e 没有:a, b, c, d, f

    f 没有:  a, b, c, d, e

    我写完之后,感觉就是把这f(n-1)的可能性加起来,就是所有的可能性。

    就想起数学里面计算排列数的方法:

    叫做乘法原理,如果一件事情,可以通过n 步完成:

    第一步:

    第一个位置有n 种可能,大家都可以放。

    第二步:

    第二个位置有n-1 种可能,因为,第一个位置定下来了。

    ...

    最后,一步,大家都定下来了,那么最后一个位置就只能放剩下来的那个了。

    虽然,这个计算过程是一步,一步的,像是一种顺序结构。但是,也可以认为是一种递归结构。

    用程序模拟就是:

    第一个位置 如果是a ,下面就是 f(n-1) 的问题了。

    第一个位置 如果是b,   下面也是f(n -1) 的问题了

    ...

    接下来,你就是绞尽脑子,怎么模拟这个过程了。

    最后想到了交换比较的好。

    就是按照顺序把元素交换到pos 位置,

    交换后,对f(n-1) 进行处理

    然后再交换回来,对下一个元素进行交换。

    直接给出代码:

    #include <stdio.h>


    #define swap(arr, i , j)\
    {\
        
    if ((i) != (j)) {\
            
    int temp;\
            temp 
    = arr[i]; \
            arr[i] 
    = arr[j]; \
            arr[j] 
    = temp;\
        }\
    }

    void print_array(int *arr, int len)
    {
        
    int i;
        printf(
    "\n");
        
    for(i  =0; i < len; i++) {
            printf(
    "%d ", arr[i]);
        }
    }

    int permutation(int *arr, int pos, int n)
    {
        
    int i;

        
    if (pos == n) { //递归结束条件
            print_array(arr, n);
            
    return;
        }

        
    for(i = pos; i < n; i++
        {  
            swap(arr, i, pos);
    //某个数字交换到 pos 位置
            permutation(arr, pos + 1, n); //对出pos 位置后面的数,进行一次全排列
            swap(arr, i, pos);//复原原来的排列,准备交换下一个数到pos 位置。  
        }
        
    return 0;
    }

    int main(int argc, char *argv[])
    {
        
    int n = 0;
        
    int i;
        
    int number[20]; //已经有2432902008176640000 种排列方法了,输出来也很难保存这样多的数据了,所以程序不能大于这个数字。

        printf(
    "input n: ");
        
    while (scanf("%d"&n)) {
            
    if (n < 1) {
                printf(
    "n must big than zero. \n");
                
    continue;
            }
            
    if (n > 20) {
                printf(
    "n too big. \n");
                
    continue;
            }
            
    for (i = 0; i < n; i++) {
                number[i] 
    = i + 1;
            }
            permutation(number, 
    0, n);
            printf(
    "\n\ninput n: ");
        }
        
    return 0;
    }

    一般的,我给大家介绍一些递归编程中,比较常用的技巧:

    1. 一般,如果,不能退到 n - 1,必须退到 n - 2 和 n -1 组合才行的,一般不要用递归。否则,计算复杂性一般都很高。

    2. 如果,你觉得一个问题可以 用nlogn 的复杂性来解决,一般验证一下:把问题对半,然后,看看,两个只问题能合并成

    这个问题的解需要多少的计算量。如果是2f(n/2) + n 那么,问题就是nlogn 的复杂度,如果,n是线性的,或者是常数,

    可以考虑递归,否则,就不要考虑了,复杂度一般会很高。

    3. 如果一个问题,可以在n的复杂度内解决,一般来说,递归的时候,是常数级别的运算。这样的问题很多,常见的算法

    是动态规划的算法。

    很多时候,用你对一个问题复杂度的直觉,倒推出算法,是一种很有意思的方法。特别是应付考试,那是相当的有效。

    (很多考试题,会要求 复杂度 是多少以内)

  • 相关阅读:
    python 测试日志的简单写法
    selenium web端滑动页面查找元素
    selenium之内嵌网页iframe切换
    selenium多窗口切换,及其关闭
    selenium 双击操作右击操作鼠标悬停
    selenium web元素定位合集
    三大浏览器的驱动地址
    app 怎么区分是原生
    django 处理图片上传
    django时区问题
  • 原文地址:https://www.cnblogs.com/niniwzw/p/1689863.html
Copyright © 2011-2022 走看看