字符串全排列

字符串全排列的两个例子:

1.abc的全排列有:

abc

acb

bac

bca

cba

cab

2.aab的全排列有:

aab

aba

baa


思路:使用回溯法。对于abc,a和a交换仍是abc;a和b交换可得bac;a和c交换可得cba,至此第一个字母的遍历结束。从上述结果中进行第二个字母的遍历:对于abc,b和b交换仍是abc,b和c交换可得acb;对于bac,a和a交换仍是bac,a和c交换可得bca;对于cba,b和b交换仍是cba,b和a交换可得cab。至此我们得到abc的全部6种排列。归纳上述方法,即:对于长度为n的字符串,需要对其第1至第n-1个字符进行遍历。所谓“遍历”是指将该位置的字符与其本身以及其后的所有字符均交换一遍,得出下一轮“遍历”的若干分支。第一轮遍历会获得n个分支,第二轮在此基础上获得n*(n-1)个分支,第三轮为n*(n-1)*(n-2)个分支,……,第n-1轮为n*(n-1)*(n-2)*……*2 = n!个分支,正符合全排列公式

上述分析只针对无重复字符的字符串。对于有重复字符的字符串上述算法不会得出正确结果,以abb为例:第一轮的一个分支是bab,另一个分支是bba。第二轮中bba的一个分支是bab,这与第一轮得到的bab重复,因此出错

我们只需对上述算法做一些改进即可适用于有重复字符的字符串,具体为:在某一轮“遍历”中,若当前准备被交换的字符在该轮已被交换过,则跳过该次交换

import java.io.BufferedInputStream;
import java.util.Scanner;
public class pangguo {
	public static void main(String args[]) {
		Scanner cin = new Scanner(new BufferedInputStream(System.in));	//输入
		String str = cin.next();
		char[] ch = str.toCharArray();
		new pangguo().process(ch,ch.length,0);
	}
	
	public  void process(char s[],int n,int k) {
		if(k == n-1)  //递归的出口,若遍历至最后一个字符,则无法再交换,打印此分支
			System.out.println(s);
		else{
			for(int i = k; i < n; i++){  //交换包括其本身及之后的所有字符
				int exist = 0;  //标记当前计划交换的字符之前是否出现过,0为未出现
				for(int j = k; j < i; j++)  //从k扫描至i-1
					if(s[j] == s[i]){
						exist = 1;
						break;
					}
				if(exist == 0){  //若未出现过,则进行交换
					swap(s,k, i);
					process(s, n,k+1);  //交换后进行递归,进行下一轮“遍历”
					swap(s,k, i);  //必须交换回来,为了本轮其他分支使用
				}
			}
		}
	}
	
	public  void swap(char[] s,int k, int i) {
	    {
	        char temp;
	        temp = s[k];
	        s[k] = s[i];
	        s[i] = temp;
	    }
	}
	
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值