全排列

作者: lesliefang | 来源:发表于2018-07-01 11:15 被阅读19次

    求全排列最简单的就是递归了
    123 的全排列共有 6 个, 123 的全排列等于以 1 开头 23 的全排列, 加上以 2 开头 13 的全排列,加上以 3 开头 21 的全排列。

    一个数列的全排列就是每一个数分别与第一个数交换(每一个数字都做一回头)后所得数列全排列的和。去掉第一个数字,后面数列的全排列怎么求???显然一样的求法,递归就行。

    什么时候结束递归呢???显然当只剩下一个数字的时候就求得了一个全排列。

    permutation.jpg
    #include <cstdio>
    
    void swap(int a[], int i, int j) {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
    
    void permutation(int a[], int begin, int end) {
        if (begin == end - 1) {
            for(int i=0; i<end; i++) {
                printf("%d",a[i]);
            }
            printf("\n");
            return;
        }
    
        // 后面的数依次与第一个数交换
        for(int i=begin; i<=end-1; i++) {
            swap(a, begin, i); // 包括自己和自己交换
            permutation(a, begin+1, end);  // 递归处理第一个数后面数列的排列
            swap(a, begin, i); // 得到一个排列后再把原来交换的数换回来,开始下一个排列的计算
        }
    }
    
    int main() {
        int a[3] = {1,2,3};
    
        permutation(a,0,3);
    
        return 0;
    }
    

    关于去重,例如 122,上面的算法仍然会输出 6 个数列,怎么去除重复的排列呢??? 网上说的是假如要交换的两个数字下标是 i, j (i 是头) 只有当 [i,j) 之间没有和 a[j] 相同的数字才交换。我也不大理解,水平太菜, 这个递归排列我都理解了好长时间????

    bool canSwap(int a[], int i,int j) {
        // 只有当 [i,j) 之间没有和 a[j] 相同的数字才交换
        for(int x=i; x<j; x++) {
            if(a[x]==a[j]) {
                return false;
            }
        }
    
        return true;
    }
    
    // 后面的数依次与第一个数交换
    for(int i=begin; i<=end-1; i++) {
        if(canSwap(a,begin,i)) {
            swap(a, begin, i); // 包括自己和自己交换
            permutation(a, begin+1, end); // 递归处理第一个数后面数列的排列
            swap(a, begin, i); // 得到一个排列后再把原来交换的数换回来,开始下一个排列的计算
        }
    }
    

    相关文章

      网友评论

          本文标题:全排列

          本文链接:https://www.haomeiwen.com/subject/ayscuftx.html