字母排列(定长)

问题:有一个长度为 nLength 的字符串 S,不考虑 S 里面有相同的字符,将 S 中出现的字符排列成长度为 nLength 的字符串,打印出所有的排列字符串(包括原串)。

如,给定 abc ,则要输出 abc,acb,bac,bca,cab,cba。

为了得到所有排列,我们采用首字符交换法,即,把后面的字符逐个与首字符交换,再把后面的字符串当作一个子问题,于是可以用递归解决,如图1所示。


图1 递归解法

给出源码:

/*
	输入字符串:inputWord
	每一次递归到最深层时组合形成的完整字符串:outputWord
	要组合的字符串的开始/结束位置:begin(inclusive) / end(exclusive)
*/
void combineAndShow(char *inputWord,char *outputWord,int begin,int end)
{
	const char FIRST_CHAR = *(inputWord + begin);
	const char LAST_OUTPUT_CHAR = *(outputWord + begin);
	char &firstCh = *(inputWord + begin);
	char &lastOutPutCh = *(outputWord + begin);
	*(outputWord + begin + 1) = '\0';
	
	if(begin == end - 1)
	{
		printf("%s\r\n",outputWord);
		return;
	}
	
	
	//原首字母不动  // 将 i = beging 的情况单独处理是因为此时 firstCh 和 currentCh 是一个变量的两个引用
	                // 使用 a ^= b;b ^= a;a ^= b;的方法用于两边是同一个变量时会有错。
	                // 如 int a = 1;  a ^= a; a ^= a; a ^= a; 这样做会将 a 置为 0;
	lastOutPutCh = firstCh;
	combineAndShow(inputWord,outputWord,begin + 1,end);
	lastOutPutCh = LAST_OUTPUT_CHAR;
	*(outputWord + begin + 1) = '\0';
	

	
	for (int i = begin + 1;i != end - 1; ++ i)	
	{
		char &currentCh = *(inputWord + i);
		
		lastOutPutCh = currentCh;

		//将 currentCh 交换到字符串的首位置
		firstCh ^= currentCh;
		currentCh ^= firstCh;
		firstCh ^= currentCh;

		combineAndShow(inputWord,outputWord,begin + 1,end);
		
		//之后要交换回来
		lastOutPutCh = LAST_OUTPUT_CHAR;
		*(outputWord + begin + 1) = '\0';
		firstCh ^= currentCh;
		currentCh ^= firstCh;
		firstCh ^= currentCh;
	}

}

int main()
{
	freopen("C:\\outPut.txt","w",stdout);
	char str [] = {"12345678"}; //这里不能用字符串常量 : char *str = "12345678";
	                            //因为后面的算法会更改这个字符串,所以要分配空间
	char outPut[9] = {0};
	combineAndShow(str,outPut,0,9);
	return 0;
}

而一般情况下,递归的复杂度比动态规划复杂度高不少,因为,递归调用有比较大的时间耗费,而且也会有很深的函数栈,耗费不少的内存空间。而迭代没有函数递归调用的负担,它保存 i - 1 次计算结果并直接用于第 i 次的计算。 所以迭代的效率一般高于递归。我们把这个解决办法换为迭代的。

为此,另外先写了一篇文章,《算法之递归,迭代,动态规划,分冶》里面归纳了递归与迭代的本质不同,既然知道不同,就知道如何去转换了。在转换为迭代的过程中,我们采用最简单的转换方法,从底向上迭代,将第 i- 1 轮的计算结果(设为 F(i-1))缓存下来用于本轮(第 i 轮)构成结果 F(i)。

定义 i 为字符串下标,设字符串为 S,S[i] 表示取 S 的第 i 个字符。

F(0) 表示字符串为 S[0] 组合的结果,

F(1) 表示字符串为 S[0],S[1] 组合的结果,

F(2) 表示字符串为 S[0],S[1],S[2]组合的结果,

F(3) 表示字符串为 S[0],S[1],S[2],S[3] 组合的结果,

每一个 F 都是一个集合(也可以称为字符串数组)。

模拟由 F(2) 得到 F(3):

1.对于 F(2) 中的每一个字符串 T 有以下步骤2:

2.将 S[3] 追加到 T 的末尾。新得到的 T 为 T'。对 T' 有步骤3

3.遍历 T' 的每一个字符,将它与 T' 最末尾的字符交换。每次交换得到一个新字符串加入 F(3)

经过这三步,便能求出 F(3)。

其实这种转换是不节实际的,因为这需要很大的空间来存放结果。




### 英文字母排列组合的方法 生成英文字母的所有排列组合可以通过递归算法实现。以下是基于 C 语言的一个具体实现方式: #### 使用递归函数生成字母组合 通过定义一个递归函数 `doPrintAllCombination`,可以枚举字符串中的所有可能组合[^1]。 ```c #include <stdio.h> #include <string.h> void swap(char* a, char* b) { char t = *a; *a = *b; *b = t; } void permute(char* str, int l, int r) { if (l == r) printf("%s\n", str); else { for (int i = l; i <= r; i++) { swap((str + l), (str + i)); permute(str, l + 1, r); swap((str + l), (str + i)); // backtrack } } } int main() { char data[] = "ABC"; int n = strlen(data); permute(data, 0, n - 1); return 0; } ``` 上述代码实现了对输入字符串 `"ABC"` 的全排列操作。它利用交换字符位置的方式逐步构建所有的排列可能性,并最终打印出来。 #### 随机生成字母组合 如果目标是从一定范围内随机生成特定长度的字母组合,则可借助伪随机数生成器完成此任务[^2]。下面是一个 Python 实现的例子: ```python import random import string def generate_random_combinations(length, count): combinations = set() while len(combinations) < count: combination = ''.join(random.choices(string.ascii_letters, k=length)) combinations.add(combination) return list(combinations) result = generate_random_combinations(8, 10) print(result) ``` 该脚本会生成指定数量的独特随机字母串,适用于创建密码或其他需要唯一性的场景。 ### 结论 无论是采用编程语言内置库还是自定义逻辑来处理英文字母排列与组合问题,都需注意边界条件以及性能优化等问题。对于较小规模的数据集来说,穷尽法通常是可行的选择;而对于大规模数据或者实时应用场合下,则应考虑更高效的策略或限制输出范围。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值