字符串全排列算法_C#版_剑指OFFER

字符串全排列算法_C#版_剑指OFFER

题目描述

题目描述
输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。
例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。
数据范围: n < 10n<10
要求: 空间复杂度 O(n!)O(n!),时间复杂度 O(n!)O(n!)
输入描述: 输入一个字符串,长度不超过10,字符只包括大小写字母。

在这里插入图片描述

思路

显然此题为递归思维。固定一个字符,依次与剩下的字符进行交换,然后固定下一个,思想类似于排列…
首先,将字符串分为两个部分,一部分为用于交换的固定串,一部分为等待交换的交换串。为方便讲解,将固定串中字符称为固定字符,交换串中的字符称为交换字符
那么其递归顺序是这样的:

  1. 固定第一个字符,与剩下交换串substr依次交换
  2. 将substr视做第一个字符串,固定substr的第一个字符,进行操作1,直到substr长度为0,结束递归
  3. 第一个固定字符使用完毕,开始固定第二个字符,与剩下的字符串substr依次交换字符值
  4. 重复上述步骤,直至所有字符都固定过

此时,会有重复字符串的问题。固定字符与交换字符相同,那就白交换了。这时可以设置不相同时才交换。
但还是会有重复问题:

比如a b1 b2,
按照思路,
第一轮
固定a
交换一次后,得到b1 a b2,substr (a,b2 ) 交换后得到b1 b2 a,(第二步)
a b1 b2交换第二次,得到b2 b1 a,此时就重复了

此时发生重复问题是因为进入递归后,substr可当做一个独立字符串,前面的固定字符串无法影响substr产生的交换字符串,显而易见地,substr字符串拥有的字母与数量相同,则会产生重复的排列
为了解决这个问题,就提前掐断字母全都相同的substr。
判断当前交换字符,与固定字符之间的串(称为中间串)是否有与其重复的字符,如果有,就取消交换。

比如a b1 c b2 d,
按照思路,
第一轮固定a,
交换第一次得到,b1 a c b2 ,
substr (a,c,b2 ) 总会得到交换串 b2,c,a
而a与b2交换后得b2 b1 c a ,此字符串进入递归后substr(b1,c,a) 肯定会产生重复排列

using System.Collections.Generic;
using System;
class Solution
{
    public List<string> Permutation(string str)
    {
        // write code here
        List<string> res = new List<string>();
        if(str.Length==0)return res;
        recursion(0,str,ref res);
        return res;
    }
    public void recursion(int fixedIdx,string str,ref List<string> res)
    {
        // write code here
        //注意 string是不可修改的,故要转换为字符串数组
        char [] newstr = str.ToCharArray();
        res.Add(str); //添加初始串
        int curIdx;
        while(fixedIdx<str.Length)
        {   //固定字符依次向前推进
            for(curIdx=fixedIdx+1;curIdx<str.Length;curIdx++)
                {
                   if(is_swap(fixedIdx,curIdx,newstr)){
                        swap(fixedIdx,curIdx,ref newstr);   //交换
                        recursion(fixedIdx+1,new string(newstr),ref res); //从此串确定的位置后一位开始递归
                        newstr=str.ToCharArray(); //复原
                    }
                }
            fixedIdx++;
        }
    }
     //防止与前面会产生的交换串重复, 递归字符串拥有的字母与数量相同,则会输出重复的排列
     //保证相似的字符串只会输出一次
    public bool is_swap(int fixedIdx,int curIdx,char[] newstr)
    {
        int idx=curIdx-1;  //依次比较中间串是否有相等字符,若有返回false,跳过这轮交换
        while(idx>=fixedIdx)
        {
            if(newstr[idx]==newstr[curIdx])
                return false;
            idx--;
        }
        return true;
    }
    //交换
    public void swap(int fixedIdx,int idx,ref char[] substr)
    {
        char tmp=substr[fixedIdx];
        substr[fixedIdx]=substr[idx];
        substr[idx]=tmp;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值