【leetcode】全排列问题+位运算+补码

说明:

原文:July 算法习题 - 字符串4(全排列和全组合)
https://segmentfault.com/a/1190000002710424
【july的算法讲解及其推荐啊,非常透彻!】

字符串的排列组合题型集合

字符串的全排列

题目

设计一个算法,输出一个字符串字符的全排列。
比如,String = “abc”
输出是"abc",“bac”,“cab”,“bca”,“cba”,“acb”

算法思想

从集合依次选出每一个元素,作为排列的第一个元素,然后对剩余的元素进行全排列,如此递归处理;

比如:首先我要打印abc的全排列,就是第一步把a 和bc交换(得到bac,cab),这需要一个for循环,循环里面有一个swap,交换之后就相当于不管第一步了,进入下一步递归,所以跟一个递归函数, 完成递归之后把交换的换回来,变成原来的字串

递归方法1(July 方法):

abc 为例子:

  1. 固定a, 求后面bc的全排列: abc, acb。 求完后,a 和 b交换; 得到bac,开始第二轮
  2. 固定b, 求后面ac的全排列: bac, bca。 求完后,b 和 c交换; 得到cab,开始第三轮
  3. 固定c, 求后面ba的全排列: cab, cba
    即递归树:
         str:   a      b        c
             ab ac   ba bc     ca cb
       result: abc acb   bac bca    cab cba
    在这里插入图片描述
public static void Permutation(char[] s, int from, int to) {
   
       if(to<=1)
           return;
       if(from == to){
   
           System.out.println(s);
       }
       else{
   
           for(int i=from;i<=to;i++){
   
               swap(s,i,from);
               Permutation(s,from+1,to);
               swap(s,from,i);
               }
       }
   }

   public static void swap(char[] s, int i, int j) {
   
       char temp = s[i];
       s[i] = s[j];
       s[j] = temp;
   }

递归方法2:

与上面算法区别:
本算法需要一个额外的存储空间存放结果(buffer),固定第一个位置是哪个元素的时候,是通过一个循环,然后看原始字符串上,每一个位置是什么元素。July的做法没有结果的buffer,都是在一个字符串上进行的操作。第一个swap的作用就是,依次拿起始字符和后面的每一个字符交换,这样就能遍历第一个位置上的所有可能字符

n个数的全排列,一共有n!种情况. (n个位置,第一个位置有n种,当第一个位置固定下来之后,第二个位置有n-1种情况…)

全排列的过程:

  • 选择第一个字符
  • 获得第一个字符固定下来之后的所有的全排列
    • 选择第二个字符
    • 获得第一+ 二个字符固定下来之后的所有的全排列

从这个过程可见,这是一个递归的过程。

还有一点需要注意是:
之前递归过程选择的字符,下一次不能再被选: 第一个位置选了a, 其他位置就不能选a了
解决方法是1. 扫描之前选择的字符 或者 2.创建一个与字符串等长的boolean数组,标记该位置对于的字符是否已经选择。若选择,则标记true; 若未选择,则标记false.
个人认为这个算法不如第一个递归方法,因为需要额外的空间;但是二者的时间复杂度是相同的,都是O(n!)。

public class Permutation {
   
    public static void permute(String str){
   
        int length = str.length();
        boolean[] used = new boolean[length];
        StringBuffer output = new StringBuffer(length);

        
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值