算法学习【5】字符串全排列

      在面试中经常遇到字符串全排列问题,现整理常见情况如下:

1、输入字符串,输出该串中所有字符能够排列出来的字符串,例输入”abc“,输出”abc、acb、bac、bca、cab 、cba“

      不考虑字符串重复,该问题是求所有字符的排列,有A(n, n) = n! 种情况,其中n是字符串长度。

      递归思路:先确定字符串(n)第一位上的字符str[0],字符串(n-1)为字符串(n)第一位后面的子字符串,对字符串(n-1)进行全排列递归,终止条件是递归到字符串(1),即子字符串长度为1。这样就完成了第一位字符为str[0]的情况,然后就需要更换第一位字符,即依次将str[0]与str[1]、str[2]、...、str[n-1]调换,完成所有情况。

      代码如下:

public class CodeFour{
	public static void main(String[] args){
		String str = "ab";
		char[] arr = str.toCharArray();
		fun1(arr, 0, str.length());
	}

	public static void fun1(char[] arr, int begin, int len){
		if(len-begin<=1){
			System.out.println(String.valueOf(arr));
			return;
		}else{
			for(int i=begin;i<len;i++){
				swap(arr,i,begin);
				fun1(arr,begin+1,len);
				swap(arr,i,begin);
			}
		}
	}

	public static void swap(char[] arr, int index1, int index2){
		char temp = arr[index1];
		arr[index1] = arr[index2];
		arr[index2] = temp;
	}
}


2、输入字符串的字符互不相同,输出与该字符串长度相同的字符串,要求字符都来自原字符串,每个字符可以重复,例输入”ab“,输出”aa、ab、ba、bb

      不考虑字符串重复,该问题是求所有字符的组合,有pow(n, n)种情况。

      递归思路:先确定字符串(n)第一位上的字符str[0],字符串(n-1)为字符串(n)第一位后面的子字符串,然后递归。与问题1不同的是,问题1中字符不能重复,因此每次递归需要交换字符位置,为了保证字符串不变每次还需要交换回来。而问题2字符是可以重复,因此需要有一个数组用于存储结果。

      代码如下:

public class CodeThree{
	static int count = 0;

	public static void main(String[] args){
		String str = "abc";
		char[] arr = str.toCharArray();
		char[] rst = new char[str.length()];
		fun2(arr, rst, 0, str.length());
	}

	public static void fun2(char[] arr, char[] rst, int begin, int len){
		if(len-begin<1){
			count++;
			System.out.println(count+": "+String.valueOf(rst));
			return;
		}else{
			for(int i=0;i<len;i++){
				rst[begin] = arr[i];
				fun2(arr,rst,begin+1,len);
			}
		}
	}
}

      面试题整理【3】中第四题也可以采用此题递归的思想实现,先找出g、9字符出现的位置然后在该位置上进行字符组合。代码可见网页http://taop.marchtea.com/01.06.html


3、输入一个字符串,输出该字符串中字符的所有组合。例,输入abc,输出a、b、c、ab、ac、bc、abc

      思路1:与上文1、2方法类似,每次删除一个字符,不过会产生很多重复的字符

      思路2:即先求C(n, m),再依次输出C(n, 1)、C(n, 2)、...、C(n, n),可参考http://blog.csdn.net/zhaojinjia/article/details/9320475

      思路3:字符串“abc”与1-7的二进制数进行与运算,每次输出二进制为1的那几位字符即可。

     思路1代码如下:

import java.util.*;

public class CodeThree{
	public static void main(String[] args){
		String str = "abc";
		fun3(new StringBuffer(str), str.length());
	}

	public static void fun3(StringBuffer sbur, int len){
		System.out.println(sbur);

		if(len<=1){
			return;
		}else{
			for(int i=0;i<len;i++){
				StringBuffer temp = new StringBuffer(sbur);
				sbur.deleteCharAt(i);
				fun3(sbur,len-1);
				sbur = temp;
			}
		}
	}
}

     思路3代码如下:

public class CodeFour{
	public static void main(String[] args){
		String str = "abc";
		fun4(str, str.length());
	}

	public static void fun4(String str, int len){
		int N = (int)Math.pow(2,len);
		for(int i=1;i<N;i++){
			String temp = Integer.toBinaryString(i);
			while(temp.length()<len){
				temp = "0"+temp;
			}
			System.out.println(temp);
			char[] arr = new char[len];
			for(int j=0;j<len;j++){
				if(temp.charAt(j)=='1'){
					arr[j]=str.charAt(j);
				}
			}
			System.out.println(String.valueOf(arr));
		}
	}
}


      对递归的一点认识:

      1、分析问题发现直接采用多个for循环能够输出想要的结果,但是for循环的个数与字符串的长度相关,字符串越长for 循环越多,这种情况就无法直接显示的写多个for循环,可以考虑采用递归的结构。

      2、递归是不断降低问题维度的过程,重点在于如何将n问题降低到n-1问题,然后不断调用自身,而不是直接考虑n问题降低到1问题。

      3、编写递归程序时,可以将问题倒过来考虑,首先找到最简单的情况作为终止条件,然后逐步扩大分析。

      4、在递归程序中,最好不要使用”n++“等自加语句,子情况递归时直接fun(n+1)即可。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值