用代码实现全排列

本文深入探讨了24点问题背后的全排列算法原理,通过实例详细解析了递归实现过程,并提供了完整的Java代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

缘由

今天主要是研究编程之美上的24点的题,结果无意中引出了这个问题,也是面试的经典问题。


排列是什么

排列表示把集合中元素的所有按照一定的顺序排列起来。那么从对于一个集合有多少种排列是在高中就学过了的。公式如下:

例如:{1, 2, 3}的全排列为:
123;132;213;231;312;321;
共6个,即3!=3*2*1=6。

代码实现

那么用代码如何实现呢?这就是主要的难点。我想了很久,以为可以让计算机模仿人的行为。大概人的行为就是如下图所示的吧:

首先取一个元素,例如取出了1,那么就还剩下{2, 3}。然后再从剩下的集合中取出一个元素,例如取出2,那么还剩下{3}。以此类推,把所有可能的情况取一遍,就是全排列了。

那如何用代码表示呢?看了代码一步一步解析:

public class Permutation {   
    public static void permutation(char[]ss,int i){   
        if(ss==null||i<0 ||i>ss.length){   
            return;   
        }   
        if(i==ss.length){   
            System.out.println(new String(ss));   
        }else{   
            for(int j=i;j<ss.length;j++){   
                char temp=ss[j];
                ss[j]=ss[i];   
                ss[i]=temp;   
                permutation(ss,i+1);   
                temp=ss[j]; 
                ss[j]=ss[i];   
                ss[i]=temp;   
            }   
        }   
    }   
    public static void main(String args[]){   
        char []ss={'a','b','c'};   
        permutation(ss,0);   
    }   
}  
上面的代码,运行可以得到正确的结果。其中核心在于:
for(int j=i;j<ss.length;j++){   
                char temp=ss[j];
                ss[j]=ss[i];   
                ss[i]=temp;   
                permutation(ss,i+1);   
                temp=ss[j]; 
                ss[j]=ss[i];   
                ss[i]=temp;   
}  
跟着思路来一遍,当第一次来到这个循环的时候,i=0。那么下面i和j的元素的互换其实没有实质的改变。
char temp=ss[j];
ss[j]=ss[i];   
ss[i]=temp;  
接着递归执行了
permutation(ss,i+1);这一步意思就是将这个问题化了子问题,那就是本来求abc的排列,现在求bc的排列,而i+1=1,就是固定了前面第一个字符,也就是a。在递归中的排列并不会影响到a,也就是已经确定的字符。

接着代码又将i和j的元素互换了一下。为什么呢?这就是难点所在。但是如果看下一个循环就非常清楚了,当j=2时,那么递归前的互换,将abc中的ab互换,变成了bac,此时,再执行递归,就固定了第一个元素b,而去求ac的排列。同样,当求完了ac的排列之后,permutation()函数返回时又会将bac变回abc,这其实是为了下一个循环做准备,这是因为当abc的下一个循环会让a与c互换,成了cba,再去求ba的全排列。

通过最简单的abc三个数字全排列的解释,应该很容易理解4、5、甚至更多的排列是如何成功运行的。

在整个过程中还有一个要点就是,前面的固定,也就是permutation(ss,i+1);的第二个参数,可以看到for循环内的j的第一个取值是根据i来决定的,所以i这个数的大小就将整个字符序列变为了两个部分。

  • 前一部分是这次求排列的过程中不动的部分
  • 从i开始的后一部分是这次求排行中会动的部分

参考博客


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值