字符串全排列

本文通过对比错误与正确代码,详细解析了一种基于回溯法的字符串全排列算法。通过引入visited数组标记字符访问状态,避免了重复输出,实现了对输入字符串的全排列输出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

输入字符串012,正确的输出结果是:
012
021
102
120
201
210

先看一下错误的代码,错误的输出结果是:
000
001
002
010
011
012
020
021
022
100
101
102
110
111
112
120
121
122
200
201
202
210
211
212
220
221
222
你可能会笑这种很愚蠢的输出结果,哈哈哈,但是代码的思路很好理解,看懂这个代码,后面的正确的代码就是根据这个错误改进的.

#include <stdio.h> 
#include <string.h>

char a[100];
int n;

char temp[100]; // 用来存放缓冲变量


void fun(int step){
	if(step==n) //走到n时就要输出temp字符串  
	{
		temp[n]='\0';
		printf("%s \n",temp);
		return;
	}
	else{
		int i;
		for(i=0;i<n;i++){
				temp[step]=a[i]; // 把第i个字符放进去,走到n时就要输出temp字符串 
				fun(step+1);
		}
	}
}

int main() { 

	scanf("%s",a);
	n=strlen(a);  // 长度
	printf("\n\n");
	
	fun(0); //从第0个开始扔进去字符
	

return 0; 
} 

上面的思路:
先用全局变量char a[100];存储输入的字符,
然后想着for循环n次,每次往char temp[] 里面挨个扔进去a[0],a[1],a[2]
在这里插入图片描述


上面的错误原因是没有标记已访问导致重复, 所以再加上visited[]数组标记已访问就可以解决问题了.


根据上面的错误代码加上标记已访问就可以写出来了:

#include <stdio.h> 
#include <string.h>

char a[100];
int n;

char temp[100]; // 用来存放缓冲变量
bool visited[100]={false}; //标记是否访问,默认未访问 


void fun(int step){
	if(step==n) //走到n时就要输出temp字符串  
	{
		temp[n]='\0';
		printf("%s \n",temp);
		return;
	}
	else{
		int i;
		for(i=0;i<n;i++){
			if(visited[i]==false){ // 如果第i个字符未访问,才去访问
				visited[i]=true; //标记已经访问,以防重复
				temp[step]=a[i]; // 把第i个字符放进去,走到n时就要输出temp字符串 
				fun(step+1);
				
				// 收回标记未访问,以便下一次再把这个字符放进去
				visited[i]=false; 
			} 
			
		}
	}
}

int main() { 

	scanf("%s",a);
	n=strlen(a);
	printf("\n\n");
	
	fun(0);
	

return 0; 
} 

思路:
先用全局变量char a[100];存储输入的字符,
然后想着for循环n次,每次往char temp[] 里面挨个扔进去a[0],a[1],a[2]…
分情况讨论:

  1. 第一次循环扔进去a[0],就是0, 然后递归,再来for循环3次 :

    1. 第一次还是要扔进去a[0],幸好a[0]标记已经访问了,已访问就跳过这次循环,否则会像上面一样输出000这种情况

    2. 第二次扔进去a[1], 再把a[1]标记已经访问,再去for循环3次:

      1. 第一次还是要扔进去a[0],幸好a[0]标记已经访问了,跳过这次循环,不然会输出010不符合
      2. 第二次要扔进去a[1], 幸好a[1]已经访问了,跳过这次循环,不然会输出011不符合
      3. 第三次要扔进去a[2], a[2]没有访问,再去递归,这时候step==n,直接输出012符合条件
    3. 第三次扔进去a[2],再把a[2]标记已经访问, 这时候已经是02… 再去递归for循环:
      这里循环,有的已经访问跳过,只有输出021了

  2. 第二次循环扔进去a[1],就是1,标记a[1]已经访问,这时候已经是1…再去递归三次循环:

    1. 第一次循环扔进去a[0],这时候已经是10…再去递归只有输出102了
    2. 第二次循环扔进去a[1],已经访问过了
    3. 第三次循环扔进去a[2],这时候已经是12…再去递归只有输出120了
  3. 第三次循环扔进去a[2],就是2

    1. 第一次循环扔进去a[0],这时候已经是20…再去递归只有输出201了
    2. 第二次循环扔进去a[1],这时候已经是21…再去递归只有输出210了
    3. 第三次循环发现a[2]已经访问过了.

最后发现这个算法时间复杂度很高,是O(n^n),只能用于10个字符以下,还多占用了一个数组,但是思路简单,考试很容易写出来答案,哪怕背也能背出来.


附录:
https://blog.youkuaiyun.com/xky140610205/article/details/68961286
别人的时间复杂度为O(n!),但是输出结果是:
0 1 2
0 2 1
1 0 2
1 2 0
2 1 0
2 0 1
结果没有按照规定的顺序排列.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值