赞
踩
题目描述
输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。
例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。
数据范围: n < 10n<10
要求: 空间复杂度 O(n!)O(n!),时间复杂度 O(n!)O(n!)
输入描述: 输入一个字符串,长度不超过10,字符只包括大小写字母。
显然此题为递归思维。固定一个字符,依次与剩下的字符进行交换,然后固定下一个,思想类似于排列…
首先,将字符串分为两个部分,一部分为用于交换的固定串,一部分为等待交换的交换串。为方便讲解,将固定串中字符称为固定字符,交换串中的字符称为交换字符。
那么其递归顺序是这样的:
此时,会有重复字符串的问题。固定字符与交换字符相同,那就白交换了。这时可以设置不相同时才交换。
但还是会有重复问题:
比如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; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。