全排列之JAVA实现

全排列的基本思想

把待全排列记录分为两个部分:
(1) 第一个记录
(2) 剩下的所有元素
所有记录的全排列就是所有可能出现在第一个位置的记录与剩下所有元素的全排列。
以[1,2,3]为例,

1,2,3的全排列可以看作是 

1,[2,3的全排列] 
  [2,3]的全排列又可以看作是 
     2,[3的全排列]—————对应123 
     3,[2的全排列]—————对应132 
2,[1,3的全排列] 
  [1,3]的全排列又可以看作是 
     1,[3的全排列]—————对应213 
     3,[1的全排列]—————对应231 
3,[2,1的全排列] 
  [2,1]的全排列又可以看作是 
     2,[1的全排列]—————对应321 
     1,[2的全排列]—————对应312

所以很明显,这就是一个递归的思想:给你部分记录,全排列就是所有可能出现在第一个位置的记录与剩下的元素的全排列,剩下的元素的全排列又是剩下的可能出现在第一个位置的元素与剩下的元素的全排列,依次重复下去….

完整代码

fullSort方法接收三个参数,数组arr,起始位置start,终止为止end,意思就是完成arr数组从start到end之间记录的全排列。
分两个步骤:
(1)确定第一位的字符
数组arr从start到end的所有记录都可以出现在第一个位置,所以直接一个for循环,考虑了这所有的情况。在for循环中,swap方法就是交换i和start位置的数,保证当前i指向的记录出现在第一个位置,也就是start指向的位置
(2)剩下的记录继续做全排列
这个就是一个递归函数的调用,只需要修改起始位置,也就是start+1,因为start的位置已经放了记录,所以只需要继续做从start+1到end的全排列即可

至于紧接着的一个swap方法是做什么的呢?因为数组传递的是地址,所以所有的修改对所有人都是共享的,因此为了保证每一次的交换不会对下一次的交换产生影响,要重新交换一下位置,也就是复原,不然对下一次的交换就有影响了

递归的终止条件就是当start==end,也就是只有一个记录需要做全排列,也就是到了最后一个记录,这就是全排列的一种情况,输入本次的记录,也就是数组arr即可。

public class Main {
    public static void main(String[] args) {
        int[] arr = { 1, 2, 3, 4 };
        fullSort(arr, 0, arr.length - 1);
    }

    public static void fullSort(int[] arr, int start, int end) {
        // 递归终止条件
        if (start == end) {
            for (int i : arr) {
                System.out.print(i);
            }
            System.out.println();
            return;
        }
        for (int i = start; i <= end; i++) {
            swap(arr, i, start);
            fullSort(arr, start + 1, end);
            swap(arr, i, start);
        }
    }

    private static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

}

接下来用全排列来解决一个实际问题吧。

题目:图书排列

题目描述:将编号为1~10的10本书排放在书架上,要求编号相邻的书不能放在相邻的位置。
请计算一共有多少种不同的排列方案。

注意,需要提交的是一个整数,不要填写任何多余的内容。

解题思路:这个题目有很多解法,这里只说明用全排列怎么解决,先求出全排列,也就是所有的排列方案,然后去掉不满足条件的情况,也就是编号相邻的书不能相邻这一条件。

完整代码如下:

public class BookSort {

    public static void main(String[] args) {
        int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        fullSort(arr, 0, arr.length - 1);
        System.out.println(res);
    }

    static int res = 0;

    static void fullSort(int[] arr, int start, int end) {
        // 递归终止条件
        if (start == end) {
            // 求出了全排列的一种情况,然后检查是否满足条件
            if (check(arr))
                res++;
            return;
        }
        for (int i = start; i <= end; i++) {
            swap(arr, start, i);
            fullSort(arr, start + 1, end);
            swap(arr, start, i);
        }
    }

    private static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    static boolean check(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            if (Math.abs(arr[i] - arr[i - 1]) == 1)
                return false;
        }
        return true;
    }

}

全排列的代码和上面的代码一样,不同的地方就是在找到全排列的一种情况时,要检查是否满足条件,也就是check方法。

运行结果:

479306
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值